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-SPHINX-PROFILES.md | 1188 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1188 insertions(+) create mode 100644 docs/FOG-SPHINX-PROFILES.md (limited to 'docs/FOG-SPHINX-PROFILES.md') 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: +- Katzenpost, *The KEMSphinx Cryptographic Packet Format*: + +- Katzenpost, *The Sphinx Cryptographic Packet Format*: + +- Katzenpost, *The Katzenpost Mix Network Wire Protocol*: + +- Katzenpost, *Katzenpost Mix Network Replay Detection*: + +- Federico Giacon, Felix Heuer, and Bertram Poettering, *KEM Combiners*, + 2018: +- NIST, *FIPS 203: Module-Lattice-Based Key-Encapsulation Mechanism Standard*, + 2024: +- RFC 7748, *Elliptic Curves for Security*: + +- 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? -- cgit v1.2.3