summaryrefslogtreecommitdiffstats
path: root/docs/FOG-SPHINX-PROFILES.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/FOG-SPHINX-PROFILES.md')
-rw-r--r--docs/FOG-SPHINX-PROFILES.md1188
1 files changed, 1188 insertions, 0 deletions
diff --git a/docs/FOG-SPHINX-PROFILES.md b/docs/FOG-SPHINX-PROFILES.md
new file mode 100644
index 0000000..f1d32de
--- /dev/null
+++ b/docs/FOG-SPHINX-PROFILES.md
@@ -0,0 +1,1188 @@
+# FOG Sphinx Profiles
+
+Status: Draft 0.1
+
+Date: 2026-08-08
+
+## 1. Purpose
+
+This document defines `FOG-SPHINX-PROFILES`, the authenticated profile
+framework for fixed-size KEMSphinx packets used by FOG.
+
+It fixes the structural packet contract, route shape, routing commands, SURB
+rules, replay behavior, wire ownership, SDK boundary, transition behavior,
+and conformance evidence required before a concrete packet suite can be
+activated.
+
+It also records one calculated but non-active candidate geometry named
+`FOG-SPHINX-CANDIDATE-MLKEM768-X25519-1`. The candidate is an engineering
+input for benchmarks and review. It is not yet `FOG-SPHINX-1`, is not
+authorized for a public network, and does not make 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-SPHINX-PROFILES` owns:
+
+- immutable packet-profile identifiers and their consensus authorization;
+- fixed KEMSphinx packet geometry and exact route length;
+- the mapping from PKI nodes to 32-byte packet node identifiers;
+- per-hop routing command sequences and command padding;
+- forward payload and SURB slots;
+- single-use reply blocks and private reply tokens;
+- replay-tag derivation, durable replay-state behavior, and retirement;
+- packet lifetime and epoch binding;
+- the logical bodies carried by FOG-WIRE packet commands;
+- parser limits, uniform failures, and key lifecycle;
+- conformance-vector and SDK requirements;
+- isolation requirements for foreign Sphinx-family bridges.
+
+This document does not own:
+
+- message-level end-to-end encryption;
+- contact, retry, acknowledgement, or application deduplication semantics;
+- entry-capsule encryption and blind-relay entry selection;
+- rendezvous capability allocation and offline return import;
+- storage capabilities or replica protocols;
+- adjacent-link Noise framing or its record size;
+- the concrete delay distribution and cover rate;
+- consensus production, signatures, or topology assignment.
+
+Those contracts belong to FOG-MESSAGING, FOG-STORAGE, the entry-capsule and
+return-rendezvous specifications, FOG-WIRE, the cover profile, and FOG-PKI.
+
+## 3. Security Boundaries
+
+KEMSphinx protects per-hop routing information and transforms the packet at
+every hop. It does not replace message-level encryption. The terminal receives
+the fixed outer FOG payload and MUST still treat the native message or storage
+operation as end-to-end encrypted unless the owning application protocol
+explicitly defines a different public object.
+
+FOG-WIRE authenticates adjacent links but does not replace KEMSphinx. A valid
+Noise connection is only a carrier for one packet whose KEMSphinx
+authentication, route command, replay status, epoch, and geometry must still
+be validated.
+
+Fixed packet size alone does not provide anonymity against timing,
+intersection, n-1, volume, active tagging, or global observation. Delay,
+traffic volume, cover traffic, topology, endpoint safety, and operator
+independence remain necessary parts of any anonymity claim.
+
+## 4. Protocol Invariants
+
+### SPHINX-INV-01: One exact profile per epoch context
+
+A packet is processed under exactly one packet profile selected by the
+accepted consensus and the authenticated FOG-WIRE epoch context. A node MUST
+NOT guess a profile from packet length, try a list of suites, negotiate a
+suite inside a packet, or fall back after failure.
+
+### SPHINX-INV-02: Four KEMSphinx hops
+
+Every core forward route and every core reply route has exactly four
+KEMSphinx hops. A shorter or longer core route is invalid even if an
+underlying Sphinx library can pad a variable path to the same header length.
+
+### SPHINX-INV-03: Entry is outside the forward mix route
+
+The forward entry is not a KEMSphinx hop. The blind relay submits an
+entry-bound capsule; the entry releases the already constructed packet only
+to its bound layer-1 node.
+
+### SPHINX-INV-04: One transform per hop
+
+An accepted KEMSphinx hop performs one and only one unwrap. No role unwraps
+two layers, forwards a packet without the required unwrap, or changes a route
+outside the authenticated command obtained from that unwrap.
+
+### SPHINX-INV-05: Fixed external geometry
+
+Every packet using one packet profile has one exact byte length. Forward,
+reply, padding, loop, drop, mailbox, and asynchronous-message packets use the
+same geometry. Source applications do not select packet sizes.
+
+### SPHINX-INV-06: Durable replay before action
+
+After successful KEM decapsulation and header authentication, a hop MUST
+atomically check and durably insert its replay identifier before scheduling,
+forwarding, terminal delivery, or returning success to an upstream worker.
+
+### SPHINX-INV-07: Single-use replies
+
+A SURB, its private decryption token, its `surb_id`, and the associated return
+rendezvous are single-use. Uncertain delivery burns them. Retrying with the
+same reply material is forbidden.
+
+### SPHINX-INV-08: No packet-layer fragmentation identity
+
+KEMSphinx packets contain no application message identifier, fragment index,
+or fragment count. Application fragmentation occurs inside the fixed opaque
+user payload under the owning end-to-end protocol.
+
+### SPHINX-INV-09: Purpose-separated keys and state
+
+Mix KEM keys, terminal KEM keys, Noise keys, entry-capsule keys, replay-state
+protection keys, SURB private tokens, message keys, and storage keys are
+distinct. Sharing one private key or replay database across roles is
+forbidden.
+
+### SPHINX-INV-10: Failure never changes topology or profile
+
+Failure cannot remove a layer, substitute the entry as a mix, route directly
+to storage, activate an old profile, send plaintext, or hand a foreign packet
+to a core parser.
+
+## 5. Terminology and Encoding
+
+Terms used in this specification:
+
+- **packet profile**: permanent mapping from a numeric identifier to exact
+ KEMSphinx primitives, geometry, commands, epoch rules, limits, and SDK
+ behavior;
+- **packet epoch context**: the epoch and accepted consensus already bound by
+ the FOG-WIRE connection carrying the packet;
+- **packet node ID**: fixed 32-byte KEMSphinx routing identifier derived from
+ one consensus-authorized node and one packet profile;
+- **forward route**: layer 1, layer 2, layer 3, then a courier or native
+ terminal;
+- **reply route**: layer 3, layer 2, layer 1, then an entry return
+ rendezvous;
+- **SURB**: a public Single Use Reply Block given to a terminal;
+- **private reply token**: Composer-only payload decryption material paired
+ with one SURB;
+- **raw replay tag**: profile-domain-separated digest of the current hop KEM
+ ciphertext;
+- **stored replay ID**: keyed local representation committed to durable replay
+ state.
+
+All integers defined directly by FOG are unsigned and encoded in network byte
+order. Fixed arrays have exactly the declared length. Reserved and padding
+bytes are zero after decryption. Parsers reject non-zero reserved bytes,
+truncation, trailing bytes, duplicate commands, reordered commands, unknown
+commands, and lengths other than the active profile's exact values.
+
+## 6. Packet Profile Registry
+
+Every `packet_profile_id` is a non-zero unsigned 32-bit integer whose meaning
+is permanent. An identifier MUST NOT be reused for changed bytes, algorithms,
+command rules, route shape, limits, or behavior.
+
+An exact profile record contains at least:
+
+```text
+[
+ packet_profile_id,
+ kemsphinx_format_id,
+ kem_suite_id,
+ primitive_suite_id,
+ packet_node_id_hash_id,
+ replay_hash_id,
+ replay_store_mac_id,
+ additional_data,
+ hop_count,
+ route_shape_id,
+ command_registry_id,
+ kem_ciphertext_length,
+ header_mac_length,
+ payload_tag_length,
+ sprp_key_material_length,
+ per_hop_routing_info_length,
+ routing_info_length,
+ header_length,
+ surb_length,
+ sphinx_plaintext_header_length,
+ user_forward_payload_length,
+ forward_payload_length,
+ packet_length,
+ delay_profile_id,
+ maximum_packet_lifetime,
+ epoch_drain_limit,
+ parser_limits_profile_id,
+ sdk_contract_id,
+ conformance_vector_set_id
+]
+```
+
+Registry metadata MAY label a reviewed profile `alpha`, `active`, `draining`,
+or `retired`, but that mutable label is not part of the immutable profile
+meaning. Only the accepted consensus authorizes actual use. An incomplete
+candidate does not receive a numeric `packet_profile_id`.
+
+The profile record is published as an immutable release artifact and its
+identifier is listed by FOG-PKI. Consensus `active_profile_ids` selects the
+exact record. Numeric parameters are not operator-tunable.
+
+One packet profile MUST be compatible with the FOG-WIRE command-shape
+registry active on every link that carries it. A consensus containing an
+incompatible pair is invalid.
+
+## 7. Epoch and Profile Selection
+
+The packet bytes do not carry a negotiable profile identifier or epoch. The
+authenticated FOG-WIRE connection context supplies:
+
+- network identity;
+- epoch;
+- accepted consensus hash;
+- link context;
+- wire profile;
+- the one packet profile mapped to that epoch and command shape.
+
+For a given link context and packet class, one epoch maps to exactly one
+packet profile. Old-epoch packets continue only on old-epoch connections
+during the bounded drain interval. A node MUST NOT trial-decrypt an old
+packet with several epoch keys.
+
+A Composer MUST NOT create a packet unless:
+
+```text
+current_time_upper_bound
+ + maximum_route_delay
+ + relay_and_entry_queue_budget
+ + wire_delivery_budget
+ < packet_epoch_hard_expiry
+```
+
+The same check applies to a SURB's expected round trip. A packet or SURB that
+cannot complete within its epoch budget is not created.
+
+## 8. Core Route Shape
+
+### 8.1 Forward route
+
+The only core forward shape is:
+
+```text
+entry capsule -> L1 -> L2 -> L3 -> terminal
+```
+
+The entry capsule is outside this four-hop KEMSphinx packet. Its specification
+must cryptographically bind the exact packet to the exact L1 packet node ID
+without revealing that ID to the blind relay.
+
+The four KEMSphinx hops are:
+
+| Hop | Required role | Required routing result |
+|---:|---|---|
+| 0 | mix layer 1 | delay, then layer 2 |
+| 1 | mix layer 2 | delay, then layer 3 |
+| 2 | mix layer 3 | delay, then selected terminal |
+| 3 | courier or native terminal | terminal recipient and payload |
+
+### 8.2 Reply route
+
+The only core reply shape is:
+
+```text
+terminal uses SURB -> L3 -> L2 -> L1 -> entry rendezvous
+```
+
+The four KEMSphinx hops are:
+
+| Hop | Required role | Required routing result |
+|---:|---|---|
+| 0 | mix layer 3 | delay, then layer 2 |
+| 1 | mix layer 2 | delay, then layer 1 |
+| 2 | mix layer 1 | delay, then entry |
+| 3 | entry | return rendezvous plus `surb_id` |
+
+The reply sender learns the public first-hop packet node ID contained in the
+SURB. It does not learn later hops, the destination relay, or the Composer's
+private reply token.
+
+### 8.3 Eligibility checks
+
+The Composer builds routes only from one accepted full consensus. Every hop
+must have the required role, exact layer, active packet profile, current epoch
+KEM key, endpoint reachability through the next role, and no effective
+revocation. The route must also pass the consensus topology and diversity
+rules.
+
+Each online hop independently verifies that the authenticated upstream role,
+its own role and layer, the next packet node ID, and the next FOG-WIRE context
+match the consensus. A valid header is not sufficient authorization for a
+role-invalid edge.
+
+## 9. Packet Node IDs
+
+KEMSphinx routing uses a fixed 32-byte `packet_node_id`. It is not a private
+key and is not a substitute for the PKI `node_id`.
+
+For profile `P`, it is derived as:
+
+```text
+packet_node_id = HASH32(
+ "FOG-SPHINX-NODE-ID-1" ||
+ u32be(length(network_id)) ||
+ network_id ||
+ u32be(P.packet_profile_id) ||
+ u32be(length(node_id)) ||
+ node_id
+)
+```
+
+`HASH32` is fixed by `packet_node_id_hash_id`. Consensus validation derives
+all active packet node IDs and rejects any duplicate. Nodes build an immutable
+epoch-local lookup table from packet node ID to the exact authorized role,
+layer, KEM key ID, and link endpoint.
+
+Packet node IDs may be logged only in coarse configuration validation. They
+MUST NOT be logged per packet.
+
+## 10. Routing Commands
+
+The core profile uses the maintained Sphinx command model with these exact
+tags:
+
+| Tag | Command | Body length | Meaning |
+|---:|---|---:|---|
+| `0x00` | `NULL` | 0 | terminates command parsing; remaining bytes are zero |
+| `0x01` | `NEXT_NODE` | 64 | 32-byte next node ID and 32-byte next header MAC |
+| `0x02` | `RECIPIENT` | 32 | opaque terminal recipient or return capability |
+| `0x03` | `SURB_REPLY` | 16 | random single-use `surb_id` |
+| `0x80` | `NODE_DELAY` | 4 | unsigned delay in profile-defined units |
+
+Unknown tags are invalid. No vendor command range is accepted by core nodes.
+
+### 10.1 Intermediate mix command sequence
+
+Every nonterminal mix hop contains exactly:
+
+```text
+NODE_DELAY || NEXT_NODE || NULL || zero padding || next KEM ciphertext
+```
+
+The implementation may build commands in an internal representation, but the
+encrypted routing bytes and parser result must preserve this semantic order.
+There is exactly one delay and one next node. Zero delay is valid only if the
+active cover profile explicitly includes it in the same public distribution
+used for real and cover packets.
+
+The `NODE_DELAY` value is validated before queue insertion. Values outside the
+active delay profile, arithmetic overflow, or a deadline past epoch expiry
+cause a uniform drop.
+
+### 10.2 Forward terminal command sequence
+
+The terminal hop contains exactly:
+
+```text
+RECIPIENT || NULL || zero padding || unused zero KEM slot
+```
+
+`RECIPIENT` is a random or derived 32-byte capability defined by the terminal
+contract. It must not be a human address, username, public mailbox name, or
+application-specific string. The terminal validates it before acting on the
+payload.
+
+### 10.3 Reply terminal command sequence
+
+The entry terminal hop contains exactly:
+
+```text
+RECIPIENT || SURB_REPLY || NULL || zero padding || unused zero KEM slot
+```
+
+Here `RECIPIENT` is an opaque short-lived return-rendezvous capability and
+`SURB_REPLY` selects the Composer's private reply token. The entry atomically
+consumes the rendezvous before queueing the returned opaque payload.
+
+### 10.4 Terminal padding
+
+The current maintained KEMSphinx geometry reserves one KEM ciphertext-sized
+tail in every per-hop routing block, including the terminal block. The
+terminal tail is all zero before routing encryption. FOG does not apply the
+possible one-ciphertext optimization until a new separately identified
+profile has complete vectors and interoperability review.
+
+## 11. Forward Plaintext Block
+
+After the terminal KEMSphinx unwrap and payload-tag validation, a forward
+payload has this exact layout:
+
+```text
+offset length field
+0 1 surb_flag
+1 1 reserved
+2 S surb_slot
+2+S U user_payload
+```
+
+`reserved` is zero. `S` is the profile's exact `surb_length`. `U` is the exact
+`user_forward_payload_length`.
+
+`surb_flag` is:
+
+- `0x00`: no usable SURB; the entire `surb_slot` is zero after decryption;
+- `0x01`: `surb_slot` contains one valid SURB for the same packet profile and
+ epoch.
+
+All other values are invalid. The slot always exists and always occupies the
+same bytes. Application code receives exactly `U` opaque bytes and an optional
+validated public SURB. It does not receive short lengths from the packet
+layer.
+
+The 4,096-byte candidate user payload is owned internally by the next
+protocol. FOG-MESSAGING or FOG-STORAGE defines authentication, actual body
+length, padding, fragmentation, retries, deduplication, and acknowledgements
+inside those bytes.
+
+## 12. SURB Contract
+
+### 12.1 Public SURB
+
+The public SURB encoding is exactly:
+
+```text
+prebuilt_kemsphinx_header[header_length] ||
+first_hop_packet_node_id[32] ||
+reply_payload_key_material[sprp_key_material_length]
+```
+
+The packet profile and epoch are supplied by the containing authenticated
+context and the local SURB object. They are not inserted into the opaque SURB
+and do not change its size.
+
+The prebuilt reply path has exactly four hops and ends in the entry terminal
+commands described in section 10.3.
+
+### 12.2 Private reply token
+
+The Composer stores, separately from the public SURB:
+
+```text
+[
+ token_version,
+ packet_profile_id,
+ epoch,
+ surb_id,
+ hard_expiry,
+ status,
+ reverse_order_payload_key_material
+]
+```
+
+For four hops, `reverse_order_payload_key_material` contains five fixed key
+and IV pairs: one per KEMSphinx hop plus the final reply payload pair. In the
+candidate geometry this secret field is 320 bytes.
+
+The token is secret Composer state. It is encrypted and integrity-protected
+at rest under the Composer state profile, excluded from logs and routine
+backups unless the backup design explicitly protects it, and erased after
+successful use, expiry, cancellation, or uncertain duplicate handling.
+
+### 12.3 Single-use state machine
+
+The only valid state transitions are:
+
+```text
+AVAILABLE -> COMMITTED -> CONSUMED
+AVAILABLE -> EXPIRED
+COMMITTED -> BURNED
+```
+
+The terminal changes a public SURB from `AVAILABLE` to `COMMITTED` before
+building or submitting a reply packet. A confirmed local construction error
+before any packet or KEM operation may return it to `AVAILABLE`; after packet
+construction or any send attempt, uncertainty results in `BURNED`.
+
+The Composer atomically changes the private token to `CONSUMED` before
+releasing successfully authenticated plaintext to an application. A second
+return with the same `surb_id` is discarded without another decryption
+attempt.
+
+Applications needing retries provide multiple independently generated SURBs.
+They never clone a SURB or its private token.
+
+### 12.4 Tagging and compulsion limits
+
+SURBs do not remove active-tagging or reply-compulsion risk. Implementations
+MUST apply the same fixed packet schedule, reply size, and terminal queue
+policy to successful replies, errors, and cover outcomes. A terminal cannot
+send arbitrary immediate diagnostic replies outside the cover schedule.
+
+## 13. Replay Protection
+
+### 13.1 Raw replay tag
+
+For an authenticated hop, the raw tag is:
+
+```text
+raw_replay_tag = HASH(
+ "FOG-SPHINX-REPLAY-TAG-1" ||
+ network_id ||
+ u32be(packet_profile_id) ||
+ u64be(epoch) ||
+ kem_key_id ||
+ current_hop_kem_ciphertext
+)
+```
+
+Lengths for variable fields are fixed by the active PKI and packet profiles.
+`HASH` and its output length are fixed by `replay_hash_id`.
+
+The current hop KEM ciphertext is the public ciphertext at the front of the
+current KEMSphinx header, not a future ciphertext hidden in routing data.
+
+### 13.2 Stored replay ID
+
+The durable database stores:
+
+```text
+stored_replay_id = MAC(
+ replay_state_key_epoch,
+ "FOG-SPHINX-REPLAY-STORE-1" || raw_replay_tag
+)
+```
+
+This local keyed representation reduces direct correlation between a stolen
+database and previously captured packet headers. It is not a substitute for
+disk, process, or host protection.
+
+`replay_state_key_epoch` is independently generated per node, packet profile,
+and epoch. It is not derived from a KEMSphinx private key and is never shared
+with another role or node.
+
+### 13.3 Processing order
+
+A hop processes an incoming packet in this order:
+
+1. verify authenticated FOG-WIRE context, exact command body, and packet
+ length;
+2. enforce current epoch, profile, role, layer, upstream, and local key ID;
+3. parse only fixed header offsets;
+4. decapsulate the current KEM ciphertext;
+5. derive hop keys and verify the current header MAC;
+6. derive the raw replay tag and stored replay ID;
+7. atomically check and durably insert the stored replay ID;
+8. parse and validate the exact routing command sequence;
+9. validate next-hop authorization and delay bounds;
+10. transform the packet exactly once;
+11. queue the transformed packet or terminal payload;
+12. erase per-hop shared secrets and temporary keys.
+
+An unauthenticated random ciphertext is not inserted. A header that
+successfully authenticates is inserted before later command validation, even
+when the command, next hop, delay, or terminal capability is invalid. This
+prevents repeated authenticated malformed work from bypassing replay state.
+
+### 13.4 Durable database
+
+Replay insertion is a crash-consistent transaction. The packet is not made
+eligible for forwarding until the write-ahead record or equivalent durable
+commit succeeds. Group commit is permitted only if scheduling and forwarding
+wait for the corresponding durable barrier.
+
+A keyed in-memory filter MAY avoid many exact lookups, but it is only a front
+cache. A positive filter result is confirmed against the exact durable set;
+therefore filter false positives do not discard valid packets.
+
+Replay databases are separated by node, role, packet profile, epoch, and KEM
+key ID. They are excluded from telemetry, snapshots shared across nodes, and
+ordinary backups. Aggregate counts may be exported only under the observer
+privacy profile.
+
+### 13.5 Restart and loss
+
+On restart, a node verifies database integrity, replay-state key availability,
+epoch ownership, and committed sequence state before accepting packets. It
+rebuilds any in-memory filter from the exact durable set.
+
+Missing, rolled-back, corrupt, or unverifiable replay state is fail-closed.
+The node stops packet processing for that profile and epoch. It does not start
+with an empty cache. Service can resume only from safely restored monotonic
+state or a new epoch with fresh KEM and replay-state keys.
+
+### 13.6 Retirement
+
+An epoch replay database and its local key are retained until:
+
+```text
+epoch_hard_expiry
+ + maximum_packet_lifetime
+ + maximum_clock_uncertainty
+ + crash_recovery_margin
+```
+
+has passed. Retirement erases the replay-state key and removes the database
+through the deployment's recoverable secure-deletion policy. No node accepts
+new work merely because an old database still exists.
+
+## 14. KEMSphinx Hop Processing
+
+Every mix worker has fixed-size buffers from its active geometry. It does not
+allocate based on decrypted command values.
+
+For a valid intermediate hop it:
+
+- decrypts the current routing block;
+- obtains the authenticated delay and next node;
+- shifts the routing information according to KEMSphinx;
+- copies the hidden next-hop KEM ciphertext into the public KEM field;
+- applies one payload permutation;
+- commits replay state;
+- enters the bounded delay queue;
+- emits the exact transformed packet on the authorized next link.
+
+For a valid terminal it:
+
+- verifies the terminal command sequence;
+- verifies the final payload integrity tag;
+- validates the fixed forward plaintext block for a forward packet, or
+ returns the still SURB-protected payload and `surb_id` for a reply packet;
+- consumes any terminal or rendezvous capability atomically;
+- hands only the bounded opaque object to the owning role contract.
+
+No mix exposes whether failure was KEM, MAC, replay, command, delay, route,
+queue, payload tag, recipient, or epoch. Remote behavior is the same uniform
+drop class and is subject to the cover schedule.
+
+## 15. Delay Contract
+
+`NODE_DELAY` contains a 32-bit count in the unit fixed by the active delay
+profile. Implementations convert using checked arithmetic and a monotonic
+clock.
+
+The delay profile fixes at least:
+
+```text
+[
+ delay_profile_id,
+ unit_nanoseconds,
+ maximum_encoded_delay,
+ maximum_per_hop_delay,
+ maximum_route_delay,
+ sampling_distribution_id,
+ quantization_rule,
+ queue_deadline_rule,
+ cover_schedule_profile_id
+]
+```
+
+The Composer samples every mix delay from this authenticated distribution.
+Operators do not alter it locally. Mixes validate the encoded value but do not
+resample it. Queue pressure does not convert delayed traffic to immediate
+traffic; overload follows the profile's uniform drop or shutdown behavior.
+
+The initial distribution and numeric limits remain simulation outputs. No
+anonymity or latency claim follows from this structural specification.
+
+`FOG-SIMULATION.md` records an initial 500 ms versus 5 second exponential-delay
+sensitivity comparison. It selects neither value. The longer value improved
+local pool overlap under one high-cover scenario while increasing modeled
+latency by roughly an order of magnitude; formal end-to-end and operational
+evidence remains open.
+
+## 16. Padding and Fragmentation
+
+### 16.1 Packet padding
+
+Routing blocks, forward SURB slots, user payloads, reply payloads, and unused
+fields always occupy their full profile lengths. Plain structural padding is
+zero before the applicable cryptographic layer. Random bytes are used only
+where the selected reviewed construction requires randomness.
+
+Application code MUST NOT create a shorter KEMSphinx payload. It supplies an
+exact fixed-size inner envelope whose internal padding is authenticated by the
+owning end-to-end protocol.
+
+### 16.2 Application fragmentation
+
+Messages larger than `user_forward_payload_length` are fragmented by
+FOG-MESSAGING or FOG-STORAGE before KEMSphinx construction. Fragment metadata
+is inside the end-to-end protected envelope. Each fragment becomes an
+independent fixed-size KEMSphinx packet with independent route randomness,
+KEM ciphertexts, replay tags, and optional SURB.
+
+KEMSphinx does not retransmit or deduplicate fragments. Reusing a packet for a
+retry is forbidden. A retry constructs a fresh packet under the application
+protocol's idempotency rules.
+
+### 16.3 FOG-WIRE fragmentation
+
+`PACKET_FORWARD` and the packet portion released from `PACKET_SUBMIT` are one
+logical FOG-WIRE message with an exact KEMSphinx packet body. FOG-WIRE may
+split that logical message across its fixed DATA records when the active wire
+profile requires it.
+
+Wire fragments are link-local and are fully reassembled, bounded, and
+authenticated before KEMSphinx parsing. They are never individually queued,
+replayed, forwarded, or stored as KEMSphinx packets.
+
+## 17. FOG-WIRE Command Bodies
+
+This document owns these logical command shapes:
+
+```text
+PACKET_FORWARD_BODY = kemsphinx_packet[packet_length]
+
+PACKET_RETURN_BODY =
+ surb_id[16] ||
+ returned_payload[payload_tag_length + forward_payload_length]
+```
+
+`PACKET_FORWARD_BODY` is used for entry-to-L1, mix-to-mix, and L3-to-terminal
+links. Link context and direction determine which role pair is legal.
+
+`PACKET_RETURN_BODY` is created only after the entry completes the final reply
+hop and atomically consumes the return rendezvous. The returned payload remains
+protected by the Composer's private reply token. The relay cannot decrypt or
+modify it successfully.
+
+`PACKET_SUBMIT_BODY` remains owned by the entry-capsule specification because
+it must hide and bind the first internal hop from the blind relay.
+
+A compatible FOG-WIRE command-shape registry has compile-time exact body
+limits for these commands. Generic byte-string RPCs are not conforming.
+
+## 18. Candidate Geometry
+
+### 18.1 Status
+
+The following profile is a calculated candidate:
+
+```text
+name = FOG-SPHINX-CANDIDATE-MLKEM768-X25519-1
+packet_profile_id = UNASSIGNED
+candidate_status = geometry-only
+```
+
+The candidate name is permanently bound to this calculated geometry. It is
+not a complete packet profile because final primitive IDs, dependency
+revisions, delay limits, replay lifetime, and conformance vector IDs are still
+unresolved. A numeric packet profile ID is assigned only after every field in
+section 6 is frozen. It will not reuse an identifier from another candidate.
+
+This candidate MUST NOT be placed in a claim-bearing public consensus until
+section 24's activation gates pass.
+
+`FOG-CRYPTO-SUITES.md` admits the exact calculated construction to
+complete-packet benchmarking but does not activate it. The unresolved
+non-KEM primitives and implementation evidence keep the complete profile
+non-active.
+
+`FOG-CRYPTO-BENCHMARKS.md` records a first-host benchmark of this exact
+geometry. Future implementations MUST preserve its strict integration
+finding: the parameterized maintained API is wrapped by a FOG boundary that
+rejects every path, packet, payload, SURB, encrypted reply, or reply-key length
+that differs from this profile before cryptographic processing. The first-host
+result does not change `geometry-only` status or assign a profile ID.
+
+### 18.2 Candidate primitive inputs
+
+The geometry calculation uses:
+
+- KEMSphinx with one KEM ciphertext per hop;
+- exactly four hops;
+- hybrid `MLKEM768-X25519` built by the maintained HPQC security-preserving
+ split-PRF combiner;
+- component and ciphertext concatenation order of X25519 hashed-ElGamal KEM
+ first, then ML-KEM-768, matching the evaluated HPQC registry despite the
+ display name; the split-PRF is order-sensitive;
+- ML-KEM-768 ciphertext length of 1,088 bytes;
+- X25519 hashed-ElGamal KEM ciphertext length of 32 bytes;
+- combined KEM ciphertext length of 1,120 bytes;
+- 32-byte packet node IDs;
+- 32-byte header MACs;
+- 16-byte SURB IDs;
+- 32-byte payload integrity tags;
+- 48-byte SPRP keys and 16-byte SPRP IVs;
+- two additional-data bytes fixed to `0x0000` for compatibility with the
+ evaluated maintained KEMSphinx format;
+- a two-byte forward plaintext header;
+- a 4,096-byte user forward payload;
+- one fixed SURB slot in every forward plaintext block.
+
+The primitive suite currently evaluated with this geometry includes the
+maintained Katzenpost KDF, header MAC, header stream, and AEZ-based payload
+SPRP parameterization. Geometry compatibility does not constitute approval of
+that primitive suite. In particular, the exact dependency revisions,
+side-channel behavior, licensing, AEZ usage, deterministic vectors, and
+independent review remain activation gates.
+
+### 18.3 Exact calculation
+
+```text
+KEM_CIPHERTEXT_LENGTH = 1088 + 32
+ = 1120
+
+NEXT_NODE_LENGTH = 1 + 32 + 32
+ = 65
+
+SURB_REPLY_LENGTH = 1 + 16
+ = 17
+
+PER_HOP_ROUTING_INFO = 65 + 17 + 1120
+ = 1202
+
+ROUTING_INFO_LENGTH = 4 * 1202
+ = 4808
+
+HEADER_LENGTH = 2 + 1120 + 4808 + 32
+ = 5962
+
+SPRP_KEY_MATERIAL = 48 + 16
+ = 64
+
+SURB_LENGTH = 5962 + 32 + 64
+ = 6058
+
+FORWARD_PAYLOAD = 2 + 6058 + 4096
+ = 10156
+
+PACKET_LENGTH = 5962 + 32 + 10156
+ = 16150
+
+PRIVATE_REPLY_KEYS = (4 + 1) * 64
+ = 320
+```
+
+### 18.4 Candidate geometry table
+
+| Field | Bytes |
+|---|---:|
+| Hop count | 4 hops |
+| Additional data | 2 |
+| KEM ciphertext | 1,120 |
+| Per-hop routing information | 1,202 |
+| Routing information | 4,808 |
+| Header MAC | 32 |
+| Header | 5,962 |
+| Payload tag | 32 |
+| Public SURB | 6,058 |
+| Forward plaintext header | 2 |
+| User forward payload | 4,096 |
+| Forward payload | 10,156 |
+| Complete KEMSphinx packet | 16,150 |
+| Private reply key material | 320 |
+
+Every arithmetic value is a protocol constant for this candidate. Runtime
+configuration cannot change it.
+
+## 19. Key Lifecycle
+
+Every mix and terminal has an independently generated KEMSphinx key for each
+authorized packet profile and epoch. Descriptors bind the public key, key ID,
+purpose, owner node, role, layer, profile, and validity interval.
+
+Private keys:
+
+- are generated with an approved operating-system randomness source;
+- are written only to role-local protected storage;
+- are loaded only by the owning role process;
+- are never copied to another layer, co-located role, authority, relay, or
+ observer;
+- are never used for Noise, entry capsules, storage, signatures, or messages;
+- remain available only for the exact old-epoch drain interval;
+- are erased after packet and replay retirement conditions both hold.
+
+Key generation and persistence are crash-safe. A descriptor is not published
+until the private key is durably available to its owner. A node never creates
+a fresh private key under an already published key ID.
+
+KEM decapsulation failures, malformed public keys, and component failures in
+a hybrid KEM are fatal to that packet. A hybrid implementation must reject
+incorrect component lengths before component decapsulation and must not reveal
+which component failed.
+
+## 20. Parser and Resource Limits
+
+Before cryptographic work, an implementation enforces:
+
+- exact logical message length;
+- exact packet profile from connection context;
+- one bounded packet buffer;
+- no recursive, compressed, map-based, or self-describing packet data;
+- no allocation based on routing commands;
+- no profile or algorithm name supplied by the peer;
+- per-connection, per-peer, per-key, and global cryptographic work budgets;
+- bounded queues and deadlines.
+
+After decryption, it enforces:
+
+- exact command count, type, order, and zero padding;
+- one legal next role and layer;
+- delay bounds and epoch completion bounds;
+- terminal capability length and one-time state;
+- exact forward block flags and zero reserved bytes;
+- exact payload and SURB lengths.
+
+Memory containing shared secrets, per-hop keys, private reply keys, and
+decrypted routing blocks is cleared promptly using the reviewed library's
+supported mechanism. Memory clearing is defense in depth and does not replace
+process isolation.
+
+## 21. Logging and Observability
+
+Core roles MUST NOT log:
+
+- packet bytes or packet digests;
+- raw replay tags or stored replay IDs;
+- KEM ciphertexts or shared secrets;
+- `surb_id`, SURBs, private reply tokens, or rendezvous capabilities;
+- per-packet routes, next-hop IDs, delay values, or fine timing;
+- terminal recipient capabilities or user payloads.
+
+Permitted local diagnostics are coarse reason counters, queue occupancy
+buckets, bounded latency histograms, replay database health state, and
+profile-level totals under FOG-OBSERVER privacy rules. Operators cannot enable
+packet tracing on a claim-bearing profile.
+
+Test builds may use deterministic vectors and verbose traces only with public
+test keys and synthetic packets. Such builds and keys are rejected by
+production configuration.
+
+## 22. SDK Boundary
+
+The stable public SDK exposes typed operations, not raw cryptographic knobs.
+It contains at least:
+
+```text
+ValidatePacketProfile(profile, consensus_context)
+DerivePacketNodeID(profile, node_id)
+BuildForwardRoute(consensus, terminal, rng)
+BuildReplyRoute(consensus, rendezvous, surb_id, rng)
+CreateSURB(profile, epoch, reply_route, rng)
+CreateForwardPacket(profile, route, fixed_payload, optional_surb, rng)
+CreateReplyPacket(profile, public_surb, fixed_payload)
+UnwrapOneHop(profile, epoch_context, private_key, exact_packet)
+DecryptSURBReply(private_token, surb_id, exact_returned_payload)
+```
+
+The SDK does not expose:
+
+- arbitrary hop counts for core profiles;
+- operator-selected algorithms or geometry;
+- raw private-key serialization through ordinary application APIs;
+- reuse or cloning of SURBs or reply tokens;
+- packet parsing without an authenticated profile and epoch context;
+- automatic foreign-profile detection;
+- application-dependent packet sizes.
+
+SURB and private-token types are move-only or guarded by an atomic persistent
+state abstraction. Copyable byte slices are not the primary API.
+
+The same reference codec and vector set are used by Composer, entry, mix,
+terminal, relay import, simulator, and conformance tools. Each executable
+still imports only the operations needed by its role.
+
+## 23. Conformance Evidence
+
+Each packet profile release includes machine-readable vectors generated with
+fixed public test entropy. The vector manifest records dependency versions,
+source revision, profile record hash, and generation command.
+
+The required vector set covers:
+
+1. packet node ID derivation;
+2. hybrid KEM component key and ciphertext lengths;
+3. complete candidate geometry arithmetic;
+4. every routing command encoding and invalid tag;
+5. zero padding and terminal unused KEM slot;
+6. one complete four-hop forward packet at every unwrap;
+7. one complete four-hop SURB reply at every unwrap and final decryption;
+8. replay tags at each hop and durable duplicate rejection;
+9. changed ciphertext, MAC, command, padding, payload tag, and SURB failures;
+10. wrong profile, epoch, role, layer, route length, and upstream failures;
+11. maximum and invalid delay values;
+12. SURB state transitions, double use, expiry, and uncertain send;
+13. replay database restart, rollback, corruption, and retirement;
+14. FOG-WIRE fragmentation and exact logical body reassembly;
+15. profile overlap with separate old and new epoch connections;
+16. cross-implementation byte equality.
+
+Property and fuzz tests additionally cover all fixed-offset parsers,
+truncations at every byte boundary, trailing bytes, unknown commands, command
+reordering, integer boundaries, malformed KEM component lengths, and queue
+resource limits.
+
+At least two independently integrated implementations must reproduce the
+complete vectors before a claim-bearing profile becomes active. Calling the
+same library through two thin wrappers is not independent evidence.
+
+## 24. Activation Gates
+
+`FOG-SPHINX-CANDIDATE-MLKEM768-X25519-1` remains non-active until all of the
+following are complete:
+
+- reproducible create, unwrap, SURB, and replay benchmarks on every supported
+ hardware class using the exact 16,150-byte geometry; the first older x86-64
+ create, unwrap, and SURB baseline is complete, while replay and the remaining
+ hardware classes are open;
+- memory, queue, storage, and maximum-throughput budgets for every role;
+- dependency revision pinning, license review, and reproducible builds;
+- review of the ML-KEM-768 implementation and X25519 adapter;
+- confirmation that the exact security-preserving combiner meets the
+ KEMSphinx hybrid-KEM requirement;
+- review of KDF, MAC, stream, payload SPRP, fragile payload-tag construction,
+ and side-channel behavior;
+- complete deterministic vectors and negative corpus;
+- fuzzing and restart-safe replay tests;
+- simulator evidence for packet size, delay, cover traffic, n-1, and long-term
+ disclosure behavior;
+- compatibility verification with the selected maintained KEMSphinx target;
+- independent protocol and implementation review;
+- a separately documented decision promoting an exact immutable record to
+ `alpha` and later `active`.
+
+Failure of a gate produces a newly named geometry candidate or a newly
+numbered complete packet profile, as applicable. It does not silently change
+this candidate.
+
+## 25. Profile Transitions
+
+A packet-profile transition follows the FOG-PKI preannouncement and bounded
+overlap rules.
+
+During overlap:
+
+- new work uses the profile mapped to the new epoch;
+- old work drains only on old-epoch FOG-WIRE connections;
+- each profile has separate KEM keys, replay-state keys, replay databases,
+ queues, command-shape registry, and SDK object types;
+- a packet is never converted in place from one profile to another;
+- a failure in the new profile does not reactivate the old profile;
+- minimum accepted profile state is monotonic.
+
+After hard expiry, old connections close, old packets and SURBs are rejected,
+private reply tokens expire, replay state completes its retention period, and
+private KEM keys are erased.
+
+Emergency retirement can stop creation and acceptance immediately, but it
+cannot downgrade. In-flight delivery may be lost.
+
+## 26. External Sphinx-Family Bridges
+
+Foreign Sphinx, KEMSphinx, Katzenpost, Nym, YAMN, SMTP, NNTP, and other network
+formats never enter a core packet parser. A bridge has:
+
+- a separate `fog-bridge-*` executable and service identity;
+- separate ports, FOG-WIRE link context, keys, writable state, queues, replay
+ domains, metrics, and deployment policy;
+- one explicitly named foreign profile and version;
+- strict parsing and resource bounds for that profile only;
+- no access to Composer plaintext or core private keys;
+- a fresh core packet constructed after policy validation, never a header
+ reinterpretation or in-place conversion;
+- explicit disclosure as a correlation and availability point.
+
+A bridge terminates one network anonymity context and originates another. It
+cannot claim end-to-end mix-path unlinkability across the boundary, even when
+the application payload remains end-to-end encrypted.
+
+Automatic port sharing, packet sniffing, trial parsing, or silent downgrade
+between core and foreign profiles is forbidden.
+
+## 27. Failure Matrix
+
+| Condition | Required behavior |
+|---|---|
+| Wrong packet length | reject before KEM work |
+| Wrong epoch or profile context | reject, no alternate-key trial |
+| KEM decapsulation failure | uniform drop |
+| Header MAC failure | uniform drop, no durable replay insertion |
+| Authenticated duplicate | uniform drop after exact replay lookup |
+| Authenticated invalid command | durable replay insert, then uniform drop |
+| Invalid next role or layer | durable replay insert, then uniform drop |
+| Invalid delay or expired deadline | durable replay insert, then uniform drop |
+| Replay commit failure | stop affected profile and epoch processing |
+| Replay state missing or rolled back | fail closed until safe restore or new epoch |
+| Delay queue overload | profile-defined uniform drop or role shutdown |
+| Final payload tag failure | uniform drop, no terminal action |
+| Invalid terminal capability | uniform drop after one-time-state rules |
+| SURB reused or expired | discard without constructing another reply |
+| Private token missing or consumed | discard returned payload |
+| Old profile failure during transition | do not fall back or extend expiry |
+| Foreign packet on core port | reject before foreign parsing |
+
+Local diagnostics use coarse stable reason classes. Remote peers receive no
+fine-grained error response.
+
+## 28. Threat Traceability
+
+| Threat-model concern | Packet-profile response |
+|---|---|
+| `TM-NET-01` traffic correlation | one fixed geometry, four hops, authenticated delay and cover profile |
+| `TM-NET-02` low anonymity set | no packet-format claim; simulator and deployment gates remain required |
+| `TM-NET-03` compromised mixes | stratified route, one transform, role validation, purpose-separated keys |
+| `TM-NET-04` replay and compulsion | durable per-hop replay, single-use SURBs and rendezvous state |
+| `TM-NET-05` tagging | authenticated header and payload processing, uniform terminal failure |
+| `TM-NET-06` profile fingerprinting | consensus-selected immutable profiles, no autodetection or negotiation |
+| `TM-PKI-02` stale consensus | epoch-bound packet context and monotonic transition state |
+| `TM-ROLE-01` role collapse | separate KEM keys, replay state, ports, commands, and bridge processes |
+| `TM-ROLE-02` relay knowledge | entry capsule hides L1; relay handles only opaque fixed packets |
+| `TM-ROLE-03` terminal exposure | terminal gets fixed opaque application payload, not source address or full route |
+| `TM-CRYPTO-01` primitive misuse | reviewed parameterized library, immutable suite record, activation gates |
+| `TM-CRYPTO-02` key reuse | role, purpose, profile, and epoch separation |
+| `TM-AVAIL-01` resource exhaustion | fixed buffers, crypto budgets, durable replay, bounded queues and failures |
+
+## 29. Residual Risks
+
+Even a conforming implementation remains exposed to:
+
+- traffic analysis from timing, volume, routes, endpoints, and sparse use;
+- n-1 and active-delay attacks by sufficiently placed malicious nodes;
+- denial of service through connection, KEM, replay-store, queue, or terminal
+ exhaustion within residual budgets;
+- endpoint or Composer compromise;
+- malicious or colluding entry, mix, terminal, relay, storage, and authority
+ operators within the threat model's residual cases;
+- reply tagging and compulsion not eliminated by SURBs;
+- implementation, dependency, side-channel, randomness, and erasure defects;
+- correlation introduced by external bridges;
+- loss caused by fail-closed replay and single-use reply behavior;
+- incorrect anonymity conclusions from a local PoC or low-traffic network.
+
+These risks must appear in deployment documentation and public claims.
+
+## 30. References
+
+- George Danezis and Ian Goldberg, *Sphinx: A Compact and Provably Secure Mix
+ Format*, 2009: <https://eprint.iacr.org/2008/475>
+- Katzenpost, *The KEMSphinx Cryptographic Packet Format*:
+ <https://katzenpost.network/docs/specs/kemsphinx/>
+- Katzenpost, *The Sphinx Cryptographic Packet Format*:
+ <https://katzenpost.network/docs/specs/sphinx/>
+- Katzenpost, *The Katzenpost Mix Network Wire Protocol*:
+ <https://katzenpost.network/docs/specs/mixnet/>
+- Katzenpost, *Katzenpost Mix Network Replay Detection*:
+ <https://katzenpost.network/docs/specs/packet_replay/>
+- Federico Giacon, Felix Heuer, and Bertram Poettering, *KEM Combiners*,
+ 2018: <https://eprint.iacr.org/2018/024>
+- NIST, *FIPS 203: Module-Lattice-Based Key-Encapsulation Mechanism Standard*,
+ 2024: <https://csrc.nist.gov/pubs/fips/203/final>
+- RFC 7748, *Elliptic Curves for Security*:
+ <https://www.rfc-editor.org/rfc/rfc7748>
+- FOG Composer protocol: `FOG-COMPOSER.md`
+- FOG cryptographic suite evaluation: `FOG-CRYPTO-SUITES.md`
+- FOG cryptographic benchmark baseline: `FOG-CRYPTO-BENCHMARKS.md`
+- FOG traffic and topology simulation: `FOG-SIMULATION.md`
+
+## 31. Completion Checklist
+
+Before implementation work for an active packet profile begins, reviewers
+must be able to answer yes to all of these questions:
+
+- Is one immutable profile selected by authenticated consensus and epoch
+ context without packet guessing?
+- Are both directions exactly four KEMSphinx hops with the entry outside the
+ forward route?
+- Are packet, header, routing, payload, SURB, and reply-token sizes proven by
+ arithmetic and tests?
+- Are command sequences exact, padded, role-valid, and parser-bounded?
+- Is replay state durable before forwarding and fail-closed after rollback or
+ loss?
+- Are SURBs, private tokens, IDs, and rendezvous capabilities atomic and
+ single-use?
+- Is application fragmentation inside end-to-end protection and independent
+ of packet size?
+- Are KEM, replay, Noise, entry, storage, and message keys purpose-separated?
+- Do FOG-WIRE command shapes and packet geometry agree exactly?
+- Are complete vectors, fuzzing, benchmarks, simulation, and independent
+ review available for the exact dependency set?
+- Are external formats isolated in separate bridge processes and disclosed as
+ correlation points?
+- Do failures stop safely without topology, profile, or plaintext fallback?