# FOG Messaging Status: Draft 0.1 Date: 2026-08-08 ## 1. Purpose This document defines `FOG-MESSAGING`, the Composer-to-Composer messaging contract for FOG native asynchronous services. It fixes the contact model, private vouchers, message-envelope framing, authentication boundary, state ownership, atomic send and receive behavior, fragmentation, retries, Composer-local deduplication, authenticated commit acknowledgments, session renewal, compromise response, and conformance gates. It also records a non-active cryptographic integration candidate named `FOG-MSG-CANDIDATE-PQXDH-TR-MLKEM768-1`. The candidate combines the published PQXDH asynchronous handshake with the published Triple Ratchet construction and its ML-KEM Braid component. It is an evaluation target, not `FOG-MESSAGING-1`, has no numeric profile identifier, is not authorized for a public network, and does not by itself establish a deployed security claim. The key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, and MAY describe normative requirements in the sense of BCP 14 when they appear in uppercase. ## 2. Scope `FOG-MESSAGING` owns: - pairwise contact identities without global usernames; - private contact identity cards and single-use receive vouchers; - initiation roles and asynchronous session establishment; - the fixed message envelope carried inside an encrypted storage record; - authenticated application frames and their fixed plaintext layout; - message-level state transitions and key lifecycle requirements; - Composer-local retry, deduplication, fragment, and acknowledgment state; - normal session renewal and identity-change behavior; - recovery behavior after compromise or stale backup restore; - the common messaging interface used by `fog-drop`, `fog-mailbox`, and `fog-im`; - parser limits, failure behavior, and conformance evidence. This document does not own: - KEMSphinx packet geometry, routes, SURBs, or packet replay state; - mailbox capability derivation, storage record encryption, replication, retention, tombstones, or empty-read behavior; - adjacent-link Noise framing; - entry capsules, return rendezvous, or transfer bundles; - the concrete cover, retry, polling, or delay distributions; - local Composer state encryption, update verification, or physical transfer; - multi-device synchronization or group messaging. Those contracts belong to `FOG-SPHINX-PROFILES`, `FOG-STORAGE`, `FOG-WIRE`, the entry and rendezvous specifications, the cover profile, `FOG-COMPOSER`, `FOG-SX`, and future `FOG-GROUP` work. ## 3. Security Boundary The sender Composer constructs a messaging envelope before any online role receives the work. The intended recipient Composer is the only role allowed to authenticate and decrypt that envelope. The full messaging envelope MUST be the protected plaintext of a fixed-size `FOG-STORAGE` record. Its prefix and ratchet header are therefore not visible to the blind relay, entry, mixes, courier, or storage replicas. KEMSphinx and Noise add independent routing and adjacent-link protections but do not replace message-level protection. FOG-MESSAGING does not hide endpoint compromise, user behavior, screenshots, malicious plaintext chosen by a contact, or disclosure by an intended recipient. Fixed envelope size also does not hide timing, polling, retries, or conversation activity unless the external traffic profile supplies sufficient cover and scheduling. ## 4. Protocol Invariants ### MSG-INV-01: No global contact identifier A contact is represented by a private pairwise identity and local user label. The core protocol MUST NOT require a global username, phone number, email address, public user directory, or stable network account. ### MSG-INV-02: Contact authentication begins out of band A voucher cannot authenticate the human or organization that delivered it. Before a contact is shown as verified, users MUST compare the complete profile-bound fingerprint through an independently authenticated channel. ### MSG-INV-03: One voucher, one initiator, one session A receive voucher authorizes exactly one designated initiator and exactly one initial session. A valid first initialization consumes it. A second different initialization using the same voucher is rejected. ### MSG-INV-04: Persist before export or release The Composer MUST durably commit a send-side ratchet transition and its exact immutable envelope before exporting it. It MUST durably commit a receive-side ratchet transition and authenticated plaintext before rendering the message or exporting an acknowledgment. ### MSG-INV-05: Retry does not advance the ratchet A retry reuses the exact previously committed end-to-end envelope. It MUST NOT derive a second message key or advance the ratchet again. FOG-STORAGE owns the immutable box and courier-request generations used to place that envelope. Every network retransmission uses new KEMSphinx packet material, route randomness, entry material, SURB, rendezvous, and reply material. ### MSG-INV-06: Online roles receive no social identifier Message IDs, session IDs, fragment IDs, application IDs, acknowledgment state, ratchet headers, and contact identities remain inside the encrypted storage record. Couriers MAY deduplicate opaque storage requests but MUST NOT receive a FOG-MESSAGING identifier. ### MSG-INV-07: Acknowledgment means durable commit An authenticated message acknowledgment means only that the receiving Composer authenticated, decrypted, validated, and durably committed an envelope. It MUST NOT mean that a human read, displayed, accepted, or acted on the content. ### MSG-INV-08: Fixed external behavior Drop, mailbox, private-message, chat, data, control, retry, and acknowledgment operations use the same consensus-authorized storage and packet classes. Application type MUST NOT select external geometry or an immediate response. ### MSG-INV-09: No automatic downgrade A contact and session use one exact messaging profile. Unknown, retired, or incompatible profiles stop processing. A failure MUST NOT activate an older handshake, classical-only mode, smaller envelope, direct route, or plaintext. ### MSG-INV-10: Recovery never clones a live ratchet Copying Composer files, restoring a stale backup, or adding a second device MUST NOT create two active copies of one ratchet. Restored conversation state enters recovery and requires a new authenticated session. ## 5. Contact Model ### 5.1 Pairwise identity Each relationship has a unique Composer-generated contact root. Reusing one root across unrelated contacts is forbidden because it creates an avoidable cross-contact correlation handle. A pairwise contact identity contains separate public keys for: - the contact root signature, which binds the contact card, exact profile, and authorized handshake identity; - the exact identity key required by the selected asynchronous handshake. The contact root does not sign ordinary message bodies. Message authenticity after session establishment comes from the selected authenticated ratchet. FOG does not claim deniability until the complete selected construction and its FOG integration have been reviewed for that property. Human-readable contact names, notes, avatars, and address-book groups are Composer-local plaintext. They MUST NOT appear in identity cards, vouchers, envelopes, capabilities, logs, or external bundles. ### 5.2 Contact identity card A `ContactIdentityCard` is a private out-of-band object with these ordered semantic fields: ```text [ object_type, format_version, messaging_profile_offer, pairwise_contact_root_public_key, handshake_identity_public_key, identity_binding, sequence, not_before, not_after, contact_root_signature ] ``` `identity_binding` MUST cover the exact handshake identity, primitive suite, profile offer, card sequence, validity interval, and a domain separator. The card MUST NOT contain a mailbox read capability or global lookup name. The displayed verification fingerprint MUST commit to the canonical complete card, the FOG network identifier, and the proposed messaging profile. The UI MUST require a complete comparison or authenticated QR scan, not a short user-selected substring. ### 5.3 Receive voucher A `ReceiveVoucher` is a private single-use capability issued by the contact that will answer the initial handshake. Its ordered semantic fields are: ```text [ object_type, format_version, voucher_id, issuer_identity_card, intended_initiator_root_commitment, messaging_profile_offer, handshake_prekey_bundle, initial_mailbox_write_grant, storage_profile_requirement, sequence, not_before, not_after, flags, issuer_contact_root_signature ] ``` The voucher ID MUST contain at least 256 bits from the Composer CSPRNG. The root commitment MUST bind the complete intended initiator contact root and the voucher domain. A claim-bearing pairwise voucher MUST NOT be bearer-capable. The prekey bundle MUST contain every one-time classical and post-quantum prekey required by the active profile. A claim-bearing FOG profile MUST NOT use a last-resort reusable post-quantum prekey. Exhaustion stops new session creation until a fresh voucher is exchanged. `initial_mailbox_write_grant` authorizes deposits only into one dedicated pairwise inbound stream. The selected storage construction MAY let its writer derive the read capability and tombstone boxes in that same stream, in which case the UI and security model MUST state that authority explicitly. The grant MUST NOT expose any other inbound or outbound stream, capability registry, identity key, recovery key, local database, or storage backup. FOG-STORAGE defines its exact construction and rotation. The issuer MUST atomically persist the voucher record, all corresponding private prekeys, the write-grant state, validity, sequence, and consumption status before the voucher can leave the Composer. Export failure does not permit a second voucher object with the same ID or private prekeys. ### 5.4 Targeted contact ceremony The initial pairwise ceremony is: 1. Both parties privately exchange `ContactIdentityCard` objects. 2. They verify the complete profile-bound fingerprints out of band. 3. They explicitly choose one session initiator. 4. The responder creates one `ReceiveVoucher` targeted to the chosen initiator root. 5. The initiator imports and validates the voucher, then prepares one initial session envelope. 6. That encrypted initial envelope carries a fresh return mailbox write grant for the responder. 7. The responder consumes the voucher only while atomically committing the valid initial session. The initiator MUST NOT create a second initial envelope from the same voucher. Until the first authenticated response is committed, only the initial content envelope may be outstanding. Later user messages remain in a local application queue. This bound prevents multiple independent initial sessions and limits replay ambiguity. ### 5.5 Bearer and one-way drop vouchers An explicitly marked bearer voucher provides weaker authentication. The first holder able to complete a valid initialization wins. Such a contact MUST be displayed as `ACTIVE_UNVERIFIED`, and the UI MUST state that possession of the voucher does not identify a person. `fog-drop` MAY use a separate one-time sealed drop voucher when the receiver does not need an authenticated sender or continuing conversation. Each drop requires an independent voucher and independent storage grant. A drop profile MUST NOT claim ratchet forward secrecy, mutual contact authentication, or post-compromise recovery that it does not implement. ## 6. Encoding of Contact Objects Contact objects use `FOG-MSG-CBOR-1`, a restricted deterministic CBOR profile: - the top-level and nested structures are arrays with fixed field order; - integers are unsigned and use their shortest encoding; - byte strings have exact profile-defined lengths; - text is forbidden except for a narrowly bounded protocol-owned ASCII label if a later exact profile requires one; - maps, floats, tags, indefinite lengths, compression, duplicate fields, unknown fields, and trailing bytes are forbidden; - one complete object is at most 65,536 bytes; - parsers re-encode a valid object and require byte-for-byte equality. Signatures cover a domain separator and the canonical array with the signature field omitted. The algorithm is selected by the exact messaging profile, not by an unauthenticated field supplied to a generic verifier. Contact objects are confidential social-graph material even though they carry public keys. They MUST NOT be published in consensus, a public directory, telemetry, logs, crash reports, or ordinary support bundles. ## 7. Messaging Profile Registry Every active messaging profile is an immutable mapping from one non-zero unsigned 32-bit identifier to exact dependencies and behavior. An identifier MUST NOT be reused after any byte layout, primitive, limit, state transition, or failure rule changes. An exact profile record includes at least: ```text [ messaging_profile_id, contact_encoding_id, contact_root_signature_suite_id, handshake_specification_and_revision, handshake_primitive_suite_id, ratchet_specification_and_revision, ratchet_primitive_suite_id, exporter_kdf_id, envelope_format_id, envelope_header_area_length, envelope_ciphertext_area_length, ratchet_aead_id, storage_profile_compatibility_id, maximum_skip, maximum_pending_messages, maximum_fragment_count, maximum_complete_message_length, maximum_concurrent_fragment_groups, retry_profile_id, retention_profile_id, parser_limits_profile_id, conformance_vector_set_id ] ``` The accepted FOG consensus authorizes usable profile IDs. Contact cards and vouchers narrow that authenticated set but cannot activate an absent profile. No party negotiates by trial, and no message advertises alternatives. An incomplete candidate does not receive a numeric ID. An implementation MUST NOT accept a candidate name where an active numeric profile ID is required. ## 8. Fixed Message Envelope ### 8.1 Storage relationship One `MessageEnvelope` is the fixed-size plaintext of one compatible encrypted FOG-STORAGE record. FOG-STORAGE MUST authenticate the entire fixed record, including all messaging padding, before exposing it to FOG-MESSAGING. For a profile with fixed ratchet header area `H` and fixed ratchet ciphertext area `C`: ```text message_envelope_length = 64 + H + C ``` Activation requires an explicit compatibility record proving: ```text message_envelope_length <= storage_record_plaintext_capacity storage_operation_length <= compatible KEMSphinx user payload capacity ``` The current 4,096-byte KEMSphinx candidate user payload is not automatically the messaging capacity. FOG-STORAGE still owns request framing, capability material, encryption overhead, and replica operation geometry. ### 8.2 Envelope prefix The exact 64-byte prefix is: ```text offset length field 0 2 envelope_format_version 2 1 envelope_kind 3 1 flags 4 4 messaging_profile_id 8 8 conversation_generation 16 32 lookup_id 48 2 actual_ratchet_header_length 50 14 reserved ``` All integers are unsigned network byte order. `flags` and `reserved` are zero in the first format. Unknown kinds, non-zero reserved values, invalid profile IDs, impossible lengths, and trailing bytes are rejected. `envelope_kind` is `INIT` or `RATCHET`. For `INIT`, `lookup_id` is the voucher ID. For `RATCHET`, it is the session ID. Both remain hidden from online roles by FOG-STORAGE encryption. The INIT handshake transcript MUST authenticate the proposed session ID, voucher ID, conversation generation, envelope prefix, complete padded header area, both contact identity bindings, and both mailbox write-grant contexts. The RATCHET associated data MUST authenticate the prefix and complete padded header area. ### 8.3 Header and ciphertext areas The ratchet header is serialized exactly as required by the active profile and right-padded with zero bytes to `H`. Its unpadded size must equal `actual_ratchet_header_length`. A parser MUST verify every padding byte after successful authentication. An INIT header MUST carry the exact upstream initialization data and one proposed 256-bit session ID generated by the initiator CSPRNG. That session ID is unique to the new conversation generation and becomes the `lookup_id` of later RATCHET envelopes after the responder authenticates and commits INIT. The fixed ciphertext area `C` contains one AEAD-protected fixed plaintext frame. The active ratchet derives the message key and nonce according to its unmodified specification and profile binding. FOG MUST NOT reuse a nonce with a key, improvise a second encryption layer with the same key, or expose a raw message key to an application module. The fixed prefix and complete padded header area are associated data. A message is not valid until the ratchet authentication, frame parsing, profile, generation, sequence, and application-state checks all succeed. ### 8.4 Encrypted plaintext frame The fixed frame header is exactly 144 bytes: ```text length field 2 frame_version 1 frame_kind 1 application_id 2 flags 2 reserved 8 conversation_generation 8 send_index 16 message_id 8 ack_base 32 ack_bitmap 16 fragment_group_id 2 fragment_index 2 fragment_count 4 complete_content_length 2 content_kind 2 content_length 32 complete_content_digest 2 control_code 2 reserved_2 N content_and_zero_padding ``` `N` is fixed by the profile. `content_length` selects the initial content bytes; every remaining byte is zero and is checked after AEAD authentication. Compression is forbidden. `frame_kind` is `DATA`, `ACK_ONLY`, or `CONTROL`. `application_id` identifies `DROP`, `MAILBOX`, or `IM` only inside the encrypted frame. Unknown values, flag bits, controls, or content kinds are critical and cause rejection. `send_index` begins at 1 for each direction and conversation generation and increases without wrap. `message_id` is an independent random 128-bit value for one envelope. It is not used by an online role or as a cryptographic key. Version 1 content kinds are strict UTF-8 text, bounded opaque bytes, and protocol control. The renderer MUST NOT interpret HTML, scripts, office documents, archives, executable formats, active links, remote resources, or embedded previews. Opaque bytes receive a neutral locally generated filename and require explicit user action before export. Typing state, presence, last-seen state, delivery timestamps, read receipts, remote avatars, automatic URL fetches, and external MIME resolution are not part of the first profile. ## 9. Fragmentation and Reassembly A semantic message larger than one frame is split by FOG-MESSAGING before ratchet encryption. Every fragment is an independent ratchet message with its own `send_index`, random `message_id`, message key, fixed envelope, storage record, KEMSphinx packet, and outer reply material. Fragments of one semantic message share: - one random 128-bit `fragment_group_id`; - the exact `fragment_count`; - a zero-based `fragment_index`; - `complete_content_length`; - a profile-selected digest of the complete unfragmented content; - the same application and content kind. The first profile MUST impose limits no larger than: - 256 fragments per semantic message; - 1,048,576 complete content bytes; - 16 incomplete fragment groups per contact; - one profile-defined total incomplete-byte budget per Composer. Exact active limits MAY be lower. They MUST be identical for all native applications using the profile. The Composer MUST durably commit all accepted fragments and verify count, indexes, length, kind, and complete digest before releasing any part to the application. Missing, conflicting, expired, oversized, or invalid groups are discarded without partial rendering and without a distinguishable network response. ## 10. Session State Machine ### 10.1 Contact and session states The minimum states are: - `INVITED`: a validated identity card or unconsumed voucher exists; - `INIT_READY`: one initial envelope may be built by the chosen initiator; - `INIT_SENT`: the immutable initial envelope is committed and may be retried; - `ACTIVE_UNVERIFIED`: the session authenticates a key but no authentic human fingerprint comparison is recorded; - `ACTIVE_VERIFIED`: the pairwise identity and session are verified; - `RENEWING`: an authenticated transition to a new profile or generation is in progress; - `FROZEN_IDENTITY_CHANGE`: an unexpected contact identity change blocks sends and ordinary receives; - `RECOVERY_REQUIRED`: restored, inconsistent, rolled-back, or suspected compromised state cannot continue; - `CLOSED`: the local relationship is intentionally terminated. State movement is monotonic except for a reviewed renewal that creates a new conversation generation. Reopening `CLOSED`, `FROZEN_IDENTITY_CHANGE`, or `RECOVERY_REQUIRED` requires an explicit new contact ceremony or recovery protocol, not a file edit or network response. ### 10.2 Initial session The initiator validates the voucher, active consensus profile, targeted root commitment, validity, sequence, prekey signatures, one-time prekey presence, and storage compatibility before creating an INIT envelope. The responder performs all parsing and cryptographic work against staged state. A valid INIT must bind the selected voucher, both pairwise identities, the proposed random session ID, conversation generation, return mailbox write grant, and initial content. Only then may the responder atomically: 1. mark the voucher consumed by the exact initial-envelope digest; 2. commit the resulting session and receive state; 3. commit the inbox content and acknowledgment state; 4. delete the consumed one-time private prekeys; 5. permit a scheduled authenticated response. An exact retry maps to the already committed result. A different INIT for a consumed voucher is rejected. Failure before the atomic commit leaves the voucher usable and does not delete its private prekeys. ### 10.3 Established session An established session has one sending and one receiving direction per conversation generation. The active profile owns the precise ratchet header, message-key derivation, skipped-key handling, and post-compromise state. Application modules never mutate a ratchet directly. They submit bounded semantic content to the messaging transaction and receive authenticated committed content from it. ## 11. Atomic State Transitions ### 11.1 Send transaction For each new envelope, the Composer MUST: 1. validate local contact, profile, queue, fragment, and generation bounds; 2. clone or transactionally stage the current sending ratchet; 3. derive exactly one message key and construct the exact fixed envelope; 4. atomically persist the new ratchet state, immutable envelope, send index, application queue transition, retry metadata, and outbox status; 5. erase the message key and discarded staged state; 6. only after successful commit, make the envelope eligible for export. A crash before step 4 produces no exportable envelope. A crash after step 4 recovers the exact envelope without deriving another message key. ### 11.2 Receive transaction For each imported storage record, the Composer MUST: 1. authenticate and decrypt the fixed FOG-STORAGE record; 2. parse the 64-byte prefix and select one local invitation or session; 3. check the keyed exact-envelope deduplication store; 4. stage the handshake or ratchet transition without modifying live state; 5. authenticate, decrypt, and strictly validate the complete frame; 6. validate generation, sequence, replay window, fragments, application bounds, and acknowledgment summary; 7. atomically persist new ratchet state, dedup state, inbox or reassembly state, receive window, and peer acknowledgment effects; 8. erase message, skipped, and discarded staged keys according to the profile; 9. only after commit, release complete content or schedule an acknowledgment. Authentication, parsing, policy, resource, or commit failure discards staged state and releases no plaintext. The network-facing outcome stays within the same coarse storage and cover class. ### 11.3 Local durability requirement Ratchet state, outbox state, voucher consumption, one-time prekey deletion, dedup insertion, and inbox commit form security-critical transactions. A profile is not conforming if its storage engine can acknowledge one of these effects while losing the others after power failure. FOG-COMPOSER defines structural encrypted local storage, commit-before-effect, and honest rollback-assurance levels. This specification requires transaction ordering but does not activate a database or external-anchor profile. ## 12. Retry and Outbox Semantics The minimum outbox states are: - `PENDING`: committed and eligible for first export; - `EXPORTED`: exported at least once and waiting for authenticated commit ACK; - `ACKED`: covered by an authenticated peer acknowledgment; - `EXPIRED`: retry age or attempt limit was reached; - `CANCELLED`: locally cancelled before export where profile rules permit; - `UNCERTAIN`: local import or durability evidence is insufficient and automatic state advancement is unsafe. An immutable message envelope in `EXPORTED` is never reconstructed. FOG-STORAGE atomically creates one immutable box record and one immutable courier request generation. Retransmissions within that generation reuse its exact storage bytes for courier deduplication, while every transmission uses a fresh KEMSphinx packet, SURB, private reply token, route, rendezvous, and entry capsule. A later storage request generation may reencrypt the same box only under the bounded FOG-STORAGE transition and nonce rules. The retry profile defines maximum attempts, maximum age, backoff classes, jitter source, queue budget, and expiry. It MUST be consensus-authenticated and validated by simulation. A real retry MUST wait for its scheduled traffic slot and MUST NOT create an immediate application-specific burst. Expiry means delivery is unknown, not that the peer certainly failed to commit. The UI MUST distinguish `ACKED`, `UNACKNOWLEDGED`, and local processing failure without claiming network certainty. ## 13. Composer-Local Deduplication The exact envelope deduplication identifier is stored only inside the Composer: ```text dedup_id = MAC(K_dedup, profile_domain || HASH(message_envelope)) ``` The active profile defines the exporter that derives `K_dedup`, the hash, MAC, domains, and key rotation. The formula is a protocol interface, not permission to select arbitrary primitives. For INIT, the voucher record also binds the first committed envelope digest. For RATCHET, the session-local dedup store is checked before attempting a ratchet transition. This permits an exact retry to be recognized after its message key has been deleted. Dedup entries persist for at least the maximum retry age plus the profile's recovery margin. Count and byte limits are mandatory. Eviction MUST NOT select entries based on application type or message content. If safe deduplication cannot be guaranteed, the session enters a coarse local error or recovery state rather than accepting a conflicting replay. Message deduplication MUST NOT be delegated to a courier or replica. Their separate bounded request replay rules operate on opaque storage operations and must not receive `message_id`, `send_index`, or `session_id`. ## 14. Authenticated Commit Acknowledgments ### 14.1 Acknowledgment window Every encrypted plaintext frame contains one fixed acknowledgment summary for the peer-to-local direction: - `ack_base` is the largest contiguous peer `send_index` durably committed; - bitmap bit 0 represents `ack_base + 1`; - bitmap bit 255 represents `ack_base + 256`; - a set bit means that exact out-of-order index is durably committed. Indexes at or below `ack_base` are acknowledged. A sender updates its outbox only after the summary arrives inside an authenticated, committed ratchet message of the expected session and generation. ### 14.2 ACK_ONLY If no data or control message is due, the Composer MAY create `ACK_ONLY` in a normal scheduled message slot. It has the same envelope and external geometry as all other frames and advances the ratchet exactly once. Receiving `ACK_ONLY` MUST NOT by itself trigger an acknowledgment. A later ordinary frame may naturally summarize its committed index, but there is no immediate ACK-of-ACK exchange. An ACK_ONLY envelope need not remain in an ack-wait outbox after its bounded export policy completes. A duplicate data envelope may cause the next scheduled summary to repeat its acknowledgment, but MUST NOT cause an immediate distinguishable reply. ### 14.3 Meaning and fragment behavior `MESSAGE_COMMIT_ACK` is the only version 1 message delivery acknowledgment. It means successful Composer commit. Network acceptance, courier success, replica quorum, relay import, display, read state, and user action are different facts and MUST NOT be presented as this acknowledgment. Acknowledging a fragment means that fragment was committed. It does not mean the complete semantic message was reassembled or displayed. ## 15. Limits and Malicious Contacts Every active profile defines exact equal limits for all native applications. The first profile MUST NOT exceed: - `maximum_skip`: 1,024 ratchet message keys; - `maximum_pending_messages`: a profile-fixed count and byte budget per contact and Composer; - `maximum_fragment_count`: 256; - `maximum_complete_message_length`: 1,048,576 bytes; - `maximum_concurrent_fragment_groups`: 16 per contact; - one 65,536-byte contact object; - unsigned 64-bit generations and sequence counters with no wrap. Skipped message keys are retained only within the exact ratchet bound and are securely deleted after use or expiry. The parser validates sizes before allocation and performs bounded cryptographic work per imported record. A malicious contact can send authenticated abusive content and attempt state, CPU, storage, fragment, skip-window, or notification exhaustion. FOG therefore requires per-contact and global quotas, explicit mute and close controls, bounded notifications, no active rendering, and no response amplification. Cryptographic authentication is not content safety. ## 16. Session Renewal and Profile Transition A normal renewal begins only inside an authenticated active ratchet. The old session carries a contact-root-signed offer that commits to the exact new profile, new conversation generation, fresh one-time initialization material, and storage transition context. Renewal is two-phase: 1. both sides durably commit and authenticate the same transition offer; 2. both sides confirm the new generation before retiring the old sending state. Old and new generations have distinct session IDs, ratchet state, dedup keys, storage grants, and outboxes. Messages MUST NOT be decrypted under both. There is no fallback from a failed new profile to an older one. An unexpected contact root or handshake identity change is not ordinary renewal. The session enters `FROZEN_IDENTITY_CHANGE`, displays both old and new profile-bound fingerprints locally, and requires fresh out-of-band verification. ## 17. Backup, Restore, and Compromise ### 17.1 Backup boundary An independently encrypted backup MAY contain pairwise contact roots, verified fingerprints, local labels, user-approved history, and metadata needed to start recovery. Backup keys remain separate from Composer state-encryption and messaging keys. An initial profile MUST treat active ratchet state, skipped message keys, unconsumed one-time prekeys, live vouchers, retry material, and live mailbox capabilities as non-resumable after a potentially stale restore. Restored conversations enter `RECOVERY_REQUIRED` and cannot send or accept ordinary ratchet traffic until a fresh authenticated session is established. This sacrifices seamless restore to prevent two restored copies from reusing message keys, accepting conflicting histories, or impersonating one live device state. ### 17.2 Suspected compromise Post-compromise ratcheting does not defeat an attacker that remains active on the Composer, controls randomness, or controls the long-term identity. On suspected endpoint or identity compromise, the user MUST replace the affected device or image, create new identity material, revoke or abandon old storage capabilities where possible, and reauthenticate contacts out of band. No UI may promise that sending a few more messages automatically removes an active attacker. ### 17.3 Multi-device exclusion The first profile supports one active Composer instance per pairwise identity. File copying, shared storage, or concurrent import on two devices is forbidden. Multi-device use requires a separate protocol with explicit device identity, session convergence, revocation, and metadata analysis. ## 18. Group Messaging Exclusion Pairwise fan-out is not a group security protocol. It leaks different delivery and membership patterns, lacks one coherent group epoch, and does not by itself define removal, update, or post-compromise semantics. Group messaging is deferred to a future `FOG-GROUP` specification. That work SHOULD evaluate Messaging Layer Security under RFC 9420 and its architecture considerations in RFC 9750, while adapting identity and delivery only through explicit FOG trust-boundary analysis. The initial `fog-im` profile is pairwise only. ## 19. Candidate Cryptographic Integration ### 19.1 Candidate definition `FOG-MSG-CANDIDATE-PQXDH-TR-MLKEM768-1` evaluates: - PQXDH revision 3 for asynchronous initial shared-secret establishment; - Double Ratchet specification revision 4 Triple Ratchet integration; - ML-KEM Braid specification revision 1 using ML-KEM-768; - the exact classical ratchet and authenticated-encryption dependencies required by those maintained specifications; - a separate FOG pairwise contact-root signature that binds, but does not replace or weaken, the exact PQXDH identity and prekey checks; - FOG fixed framing, atomic storage rules, voucher policy, and outer FOG-STORAGE protection defined in this document. The candidate requires one-time classical and signed one-time ML-KEM prekeys. FOG deliberately excludes the reusable last-resort PQ prekey from a claim-bearing profile. Loss of fresh vouchers therefore affects availability. ### 19.2 Claims deliberately withheld The candidate does not yet establish: - post-quantum authentication, because the reviewed PQXDH authentication claim still depends on the specified classical authentication assumptions; - complete FOG post-quantum security merely from ML-KEM inclusion; - deniability; - post-compromise recovery under message loss or continued active compromise; - safe backup, multi-device, or group behavior; - compatibility with the calculated 4,096-byte KEMSphinx payload; - implementation or side-channel safety. ### 19.3 Activation gates Before promotion to an active numeric profile, FOG MUST freeze and verify: 1. exact upstream specification revisions and all primitive identifiers; 2. one maintained implementation strategy with constant-time and secret deletion review; 3. byte-exact PQXDH, Triple Ratchet, ML-KEM Braid, FOG envelope, and contact object serialization; 4. transcript and domain separation, including the outer pairwise root binding; 5. exact header area, ciphertext area, content capacity, and storage geometry; 6. loss, reordering, skip-window, retry, crash, restore, and compromise state transitions; 7. deterministic positive and negative vectors at every boundary; 8. fuzzing and resource tests for all untrusted inputs; 9. primitive, integration, side-channel, and lifecycle review; 10. independent security review before a public security claim. FOG MUST preserve the upstream constructions rather than silently changing their KDF inputs, message-key combination, epoch behavior, or prekey checks. Any required departure creates a separately analyzed candidate. ## 20. Key and Secret Lifecycle | Material | Owner | Persistence | Required destruction or transition | | --- | --- | --- | --- | | Pairwise contact root private key | one Composer identity | long-term encrypted state; separately encrypted backup MAY be allowed | replace on compromise or explicit identity migration | | Handshake identity private key | one Composer pairwise identity | long-term encrypted state | replace with contact root on compromise | | Signed classical prekey | voucher issuer Composer | bounded by voucher and profile validity | delete after expiry and all bound voucher states retire | | Classical one-time prekey | voucher issuer Composer | persisted before voucher export | delete atomically after valid INIT commit | | ML-KEM one-time prekey | voucher issuer Composer | persisted before voucher export | delete atomically after valid INIT commit | | Initiator ephemeral handshake secrets | initiator Composer | transaction only | erase after committed initial state and envelope | | Handshake shared secrets | both Composers | transaction only | erase after ratchet and exporter state is derived | | Classical ratchet private key | one session direction | encrypted mutable session state | erase when the reviewed ratchet transition permits | | ML-KEM Braid state | one session | encrypted mutable session state | erase retired epochs and session on close or recovery | | Chain key | one session direction | encrypted mutable session state | replace and erase on every chain advance | | Message key | one envelope | transaction only | erase after durable send ciphertext or receive commit | | Skipped message key | receiving Composer | bounded encrypted state | erase on use, expiry, bound overflow, or session retirement | | Session dedup key | one session generation | encrypted mutable state | erase after retry and recovery retention ends | | Pairwise inbound stream writer grant | authorized remote contact | deposits, reads where derivable, and tombstones only in that dedicated stream | abandon and replace through FOG-STORAGE rules after compromise or closure | | Pairwise inbound stream reader state | receiving Composer; writer MAY derive under selected profile | read, verify, and advance that dedicated stream | never expose access to any other stream or capability registry | | Local state-encryption key | Composer profile | protected local state | separate from message, storage, and backup keys | | Backup key | user recovery domain | outside backup ciphertext | never derive from a contact or ratchet key | Secret values, plaintext, capabilities, contact objects, fingerprints, session IDs, message IDs, ratchet headers, and envelope digests MUST NOT enter logs, metrics, command arguments, crash reports, or support artifacts. ## 21. Failure Behavior Externally observable failures are coarse and non-amplifying. Online roles do not learn whether a storage record held an INIT, data fragment, duplicate, ACK_ONLY, invalid ratchet message, or cover object. The Composer MAY show a local reason such as invalid voucher, verification needed, incompatible profile, authentication failure, resource limit, stale state, or recovery required. It MUST NOT automatically send an error message to an unverified or unauthenticated source. Unknown-critical fields, malformed UTF-8, invalid padding, overflow, counter wrap, conflicting fragment metadata, excessive skips, expired vouchers, identity changes, state rollback, and storage commit uncertainty fail closed. Failure MUST NOT alter packet size, route length, polling rate, or security profile outside the authenticated cover policy. ## 22. Conformance and Test Requirements Before the local PoC, FOG-MESSAGING requires tests or vectors for: - canonical contact card and voucher encoding and rejection; - profile-bound fingerprint derivation and targeted voucher checks; - issue-before-export and consume-once voucher transactions; - exact 64-byte prefix and 144-byte frame header; - every envelope kind, frame kind, application ID, and content kind; - prefix, header-padding, frame-padding, transcript, and generation binding; - send crash before commit and after commit; - receive crash before commit and after commit; - exact retry without a second ratchet advance; - immutable storage request retransmission with fresh KEMSphinx, SURB, rendezvous, route, and entry material; - exact duplicate, conflicting INIT, replay, old generation, and excessive skip handling; - ACK base and bitmap boundaries, reordering, loss, duplicate data, and no ACK-of-ACK trigger; - fragment loss, duplication, conflict, timeout, digest failure, and quota exhaustion; - malicious contact CPU, memory, disk, notification, and parser bounds; - normal renewal, profile transition, identity change, stale restore, and suspected compromise; - secure deletion instrumentation where the platform can provide evidence; - candidate upstream and FOG integration vectors; - absence of prohibited fields in logs, telemetry, storage requests, and external bundles; - identical external geometry and scheduling class across native apps, retries, ACKs, and cover operations. Tests MUST include deterministic positive and negative vectors, property tests, fuzzing, transaction fault injection, power-loss simulation, and cross-implementation checks before profile activation. ## 23. Threat and Architecture Traceability | Requirement | Primary controls | | --- | --- | | `ARC-002` | networkless Composer owns every contact, ratchet, plaintext, and envelope transition | | `ARC-004` | message envelope remains independent from KEMSphinx and Noise | | `ARC-006` | fixed storage and packet classes hide native application selection from core roles | | `ARC-007` | pairwise, ratchet, storage, transport, node, and backup keys have distinct owners and purposes | | `ARC-008` | strict object, envelope, queue, fragment, skip, retry, and parser bounds | | `ARC-009` | authentication, state, and profile failures stop without bypass or downgrade | | `IF-01` | only a committed immutable envelope may enter a Composer export bundle | | `IF-02` | imported storage results are untrusted until storage and messaging validation commit | | `IF-08` | courier receives only an opaque storage operation, never messaging fields | | `IF-09` | storage carries a fixed encrypted record whose plaintext is the message envelope | | `TM-NET-02` | directional pairwise stream grants, external schedule, encrypted messaging identifiers, no immediate ACK | | `TM-NET-04` | exact-envelope dedup, consume-once voucher, fresh outer retry material | | `TM-NET-05` | authenticated ratchet and transcript, strict padding and generation binding | | `TM-NET-06` | consensus-authorized immutable profile and application-independent behavior | | `TM-ENDPOINT-01` | networkless state owner, transaction ordering, recovery freeze | | `TM-ENDPOINT-03` | no live-ratchet backup restore or file-copy multi-device state | | `TM-APP-01` | authenticated complete reassembly, bounded content, no active rendering | | `TM-OPS-01` | no contact, capability, identifier, digest, payload, or ratchet data in telemetry | | `TM-CRYPTO-01` | exact lifecycle table, purpose separation, secure deletion requirements | | `TM-CRYPTO-02` | fixed profiles, no trial negotiation, fallback, or candidate activation | | `TM-AVAIL-01` | bounded retries, skip windows, fragments, queues, contact objects, and non-amplifying errors | ## 24. Open Dependencies The structural messaging contract is fixed, but these dependencies remain open before an active profile or daemon: - exact primitive suite, dependency revisions, and maintained implementation for `FOG-MSG-CANDIDATE-PQXDH-TR-MLKEM768-1`; - license, API-support, Rust integration, panic, secret-lifecycle, and formal artifact review for the selected messaging implementation path; - exact contact-root signature and fingerprint representation; - byte-exact candidate serialization and integration vectors; - exact fixed `H`, `C`, content capacity, and lower active limits; - activation evidence and byte-exact geometry for the structural FOG-STORAGE contract and its non-active BACAP/Pigeonhole candidate; - authenticated retry, cover, polling, and expiration distributions; - activation evidence for the structural FOG-COMPOSER vault, database, external-anchor, recovery, and update-consumer profiles; - identity revocation and fresh-session recovery ceremony; - future multi-device and group protocols. No implementation convenience may silently resolve these dependencies. ## 25. Primary References - Signal PQXDH specification, revision 3: - Signal Double Ratchet specification, revision 4: - Signal ML-KEM Braid specification: - Signal Sesame asynchronous session management specification: - NIST FIPS 203, Module-Lattice-Based Key-Encapsulation Mechanism Standard: - Katzenpost contact voucher specification: - Katzenpost contact voucher narration: - RFC 9420, The Messaging Layer Security Protocol: - RFC 9750, The Messaging Layer Security Architecture: - FOG threat model: `FOG-THREAT-MODEL.md` - FOG architecture: `FOG-ARCHITECTURE.md` - FOG Sphinx profile framework: `FOG-SPHINX-PROFILES.md` - FOG storage protocol: `FOG-STORAGE.md` - FOG Composer protocol: `FOG-COMPOSER.md` - FOG cryptographic suite evaluation: `FOG-CRYPTO-SUITES.md` These references supply maintained constructions and design lessons. They do not make the FOG integration secure by inheritance. FOG still requires exact profiles, compatibility calculations, vectors, tests, lifecycle analysis, simulation, implementation review, and independent security review.