From 25356debcce4118cdfa86842029278fde1e64518 Mon Sep 17 00:00:00 2001 From: Gab <24553253+gabrix73@users.noreply.github.com> Date: Tue, 18 Aug 2026 21:43:48 +0200 Subject: Publish FOG design documentation and Merkle tree --- docs/FOG-MESSAGING.md | 1013 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1013 insertions(+) create mode 100644 docs/FOG-MESSAGING.md (limited to 'docs/FOG-MESSAGING.md') diff --git a/docs/FOG-MESSAGING.md b/docs/FOG-MESSAGING.md new file mode 100644 index 0000000..69b1ffd --- /dev/null +++ b/docs/FOG-MESSAGING.md @@ -0,0 +1,1013 @@ +# 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. -- cgit v1.2.3