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