From 9d11a22901ffe9c3ab0007f58baa55b0e08abfc9 Mon Sep 17 00:00:00 2001 From: AkshayaMani Date: Wed, 10 Dec 2025 07:24:23 -0500 Subject: [PATCH 1/6] docs: finalize Section 8 Sphinx Packet Construction and Handling (#202) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR builds on PR #173 and completes the remaining construction and runtime processing logic in `Section 8` of the Mix Protocol RFC. It finalizes the last steps of packet construction (`Section 8.5.2 step 3. e–f`) and introduces the complete mix node handler logic in `Section 8.6`, including intermediary and exit processing. It clearly separates construction, role determination, and processing logic. ### Changes Introduced in This PR - **8.5.2 Construction Steps (Final Steps Added)** - Sphinx packet construction - [x] Assemble Final Packet - [x] Transmit Packet - **8.6 Sphinx Packet Handling** - [x] **8.6.1 Shared Preprocessing** - Derives session key, validates replay tag and MAC, decrypts header/payload - [x] **8.6.2 Node Role Determination** - Inspects decrypted header prefix and padding to classify node as intermediary or exit - [x] **8.6.3 Intermediary Processing** - Parses next hop address and mean delay - Updates ephemeral key and routing fields - Samples actual forwarding delay and transmits packet - Erases all temporary state. - [x] **8.6.4 Exit Processing** - Verifies payload padding and extracts destination address - Parses and validates application-layer message - Hands off to Exit Layer along with origin protocol codec and destination address ### Highlights - Explicit role determination via zero-delay and padding inspection - Fully decoupled construction and handling logic - Forwarding delay behavior updated: - Sender selects per-hop mean delay - Mix node samples actual delay using pluggable distribution --------- Co-authored-by: kaiserd <1684595+kaiserd@users.noreply.github.com> --- vac/raw/mix.md | 449 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 415 insertions(+), 34 deletions(-) diff --git a/vac/raw/mix.md b/vac/raw/mix.md index a60c2ce..4b6198d 100644 --- a/vac/raw/mix.md +++ b/vac/raw/mix.md @@ -87,8 +87,7 @@ A per-message flag set by the origin protocol to indicate that a message should be routed using the Mix Protocol or not. Only messages with mixify set are forwarded to the Mix Entry Layer. -Other messages SHOULD be routed using the origin protocol’s default behavior. - +Other messages SHOULD be routed using the origin protocol’s default behavior. The phrases 'messages to be mixified', 'to mixify a message' and related variants are used informally throughout this document to refer to messages that either have the @@ -1100,8 +1099,10 @@ For interoperability, a recommended default encoding format involves: - Port number (2 bytes) - Peer IDs (39 bytes, post-Base58 decoding) -- Encoding the forwarding delay as an unsigned 16-bit integer (2 bytes) in - milliseconds, using big endian network byte order. +- Encoding the forwarding delay as an unsigned 16-bit integer (2 bytes), + representing the mean delay in milliseconds for the configured delay + distribution, using big endian network byte order. + The delay distribution is pluggable, as defined in [Section 6.2](#62-delay-strategy). If the encoded address or delay is shorter than its respective allocated field, it MUST be padded with zeros. If it exceeds the allocated size, it @@ -1165,20 +1166,24 @@ The construction MUST proceed as follows: 1. **Prepare Application Message** - Apply any configured spam protection mechanism (_e.g.,_ PoW, VDF, RLN) - to the serialized message. Spam protection mechanisms are pluggable as defined - in [Section 6.3](#63-spam-protection). + to the serialized message. Spam protection mechanisms are pluggable as defined + in [Section 6.3](#63-spam-protection). - Attach one or more SURBs, if required. Their format and processing are - specified in [Section X.X]. - - Append the origin protocol codec. + specified in [Section X.X]. + - Append the origin protocol codec in a format that enables the exit node to + reliably extract it during parsing. A recommended encoding approach is to + prefix the codec string with its length, encoded as a compact varint field + limited to two bytes. Regardless of the scheme used, implementations MUST + agree on the format within a deployment to ensure deterministic decoding. - Pad the result to the maximum application message length of $3968$ bytes - using a deterministic padding scheme. This value is derived from the fixed - payload size in [Section 8.3.2](#832-payload-size) ($3984$ bytes) minus the - security parameter $κ = 16$ bytes defined in - [Section 8.2](#82-cryptographic-primitives). The chosen scheme MUST yield a - fixed-size padded output and MUST be consistent across all mix nodes to - ensure correct interpretation during unpadding. For example, schemes that - explicitly encode the padding length and prepend zero-valued padding bytes - MAY be used. + using a deterministic padding scheme. This value is derived from the fixed + payload size in [Section 8.3.2](#832-payload-size) ($3984$ bytes) minus the + security parameter $κ = 16$ bytes defined in + [Section 8.2](#82-cryptographic-primitives). The chosen scheme MUST yield a + fixed-size padded output and MUST be consistent across all mix nodes to + ensure correct interpretation during unpadding. For example, schemes that + explicitly encode the padding length and prepend zero-valued padding bytes + MAY be used. - Let the resulting message be $m$. 2. **Select A Mix Path** @@ -1220,8 +1225,8 @@ The construction MUST proceed as follows: \end{aligned} `$ - Note that the length of $α_i$ is $32$ bytes as defined in - [Section 8.3](#83-packet-component-sizes). + Note that the length of $α_i$ is $32$ bytes, $0 \leq i \leq L-1$ as defined in + [Section 8.3.1](#831-header-field-sizes). b. **Compute Per-Hop Filler Strings** Filler strings are encrypted strings that are appended to the header during @@ -1246,17 +1251,17 @@ The construction MUST proceed as follows: - Compute the filler string $Φ_i$ using $\text{AES-CTR}^\prime_i$, which is AES-CTR encryption with the keystream starting from - index $((t+1)(r-i)+t+2)\kappa$ : + index $((t+1)(r-i)+t+2)κ$ : $` \begin{array}{l} Φ_i = \mathrm{AES\text{-}CTR}'_i\bigl(Φ_{\mathrm{aes\_key}_{i-1}}, - Φ_{\mathrm{iv}_{i-1}}, Φ_{i-1} \mid 0_{(t+1)\kappa} \bigr), + Φ_{\mathrm{iv}_{i-1}}, Φ_{i-1} \mid 0_{(t+1)κ} \bigr),\; \; \; \text{where notation $0_x$ defines the string of $0$ bits of length $x$.} \end{array} `$ - Note that the length of $Φ_i$ is $(t+1)i\kappa$. + Note that the length of $Φ_i$ is $(t+1)iκ$, $0 \leq i \leq L-1$. c. **Construct Routing Header** The routing header as defined in @@ -1286,21 +1291,22 @@ The construction MUST proceed as follows: `$ - Set the per hop two-byte encoded delay $\mathrm{delay}_i$ as defined in - [Section 8.4](#84-address-and-delay-encoding): + [Section 8.4](#84-address-and-delay-encoding): - If final hop (_i.e.,_ $i = L - 1$), encode two byte zero padding. - - For all other hop $i,\ i < L - 1$, sample a forwarding delay - using the delay strategy configured by the application and encode it in two bytes. - The delay strategy is pluggable as defined in [Section 6.2](#62-delay-strategy). + - For all other hop $i,\ i < L - 1$, select the mean forwarding delay + for the delay strategy configured by the application, and encode it as a + two-byte value. The delay strategy is pluggable, as defined in + [Section 6.2](#62-delay-strategy). - Using the derived keys and encoded forwarding delay, compute the nested - encrypted routing information $β_i$: + encrypted routing information $β_i$: - If $i = L-1$ (_i.e.,_ exit node): $` \begin{array}{l} β_i = \mathrm{AES\text{-}CTR}\bigl(β_{\mathrm{aes\_key}_i}, - β_{\mathrm{iv}_i}, Δ \mid \mathrm{delay}_i \mid 0_{((t+1)(r-L)+2)\kappa} + β_{\mathrm{iv}_i}, Δ \mid \mathrm{delay}_i \mid 0_{((t+1)(r-L)+2)κ} \bigr) \bigm| Φ_{L-1} \end{array} `$ @@ -1310,13 +1316,15 @@ The construction MUST proceed as follows: $` \begin{array}{l} β_i = \mathrm{AES\text{-}CTR}\bigl(β_{\mathrm{aes\_key}_i}, - β_{\mathrm{iv}_i}, \mathrm{addr}_{i+1} \mid $\mathrm{delay}_i$ - \mid γ_{i+1} \mid β_{i+1 \, [0 \ldots (r(t+1) - t)\kappa - 1]} \bigr) + β_{\mathrm{iv}_i}, \mathrm{addr}_{i+1} \mid \mathrm{delay}_i + \mid γ_{i+1} \mid β_{i+1 \, [0 \ldots (r(t+1) - t)κ - 1]} \bigr),\; \; \; + \text{where notation $X_{[a \ldots b]}$ denotes the substring of $X$ + from byte offset $a$ to $b$, inclusive, using zero-based indexing.} \end{array} `$ - Note that the length of $\beta_i$ is $(r(t+1)+1)\kappa$, $0 \leq i \leq L-1$ - as defined in [Section 8.3](#83-packet-component-sizes). + Note that the length of $\beta_i$ is $(r(t+1)+1)κ$, $0 \leq i \leq L-1$ + as defined in [Section 8.3.1](#831-header-field-sizes). - Compute the message authentication code $γ_i$: @@ -1327,8 +1335,8 @@ The construction MUST proceed as follows: \end{array} `$ - Note that the length of $\gamma_i$ is $\kappa$ as defined in - [Section 8.3](#83-packet-component-sizes). + Note that the length of $\gamma_i$ is $κ$, $0 \leq i \leq L-1$ as defined in + [Section 8.3.1](#831-header-field-sizes). d. **Encrypt Payload** The encrypted payload $δ$ contains the message $m$ defined in Step 1, @@ -1357,7 +1365,7 @@ The construction MUST proceed as follows: $` \begin{array}{l} δ_i = \mathrm{AES\text{-}CTR}\bigl(δ_{\mathrm{aes\_key}_i}, - δ_{\mathrm{iv}_i}, 0_{\kappa} \mid m + δ_{\mathrm{iv}_i}, 0_{κ} \mid m \bigr) \end{array} `$ @@ -1370,3 +1378,376 @@ The construction MUST proceed as follows: δ_{\mathrm{iv}_i}, δ_{i+1} \bigr) \end{array} `$ + + Note that the length of $\delta_i$, $0 \leq i \leq L-1$ is $|m| + κ$ bytes. + + Given that the derived size of $\delta_i$ is $3984$ bytes as defined in + [Section 8.3.2](#832-payload-size), this allows $m$ to be of length + $3984-16 = 3968$ bytes as defined in Step 1. + + e. **Assemble Final Packet** + The final Sphinx packet is structured as defined in + [Section 8.3](#83-packet-component-sizes): + + ```text + α = α_0 // 32 bytes + β = β_0 // 576 bytes + γ = γ_0 // 16 bytes + δ = δ_0 // 3984 bytes + ``` + + Serialize the final packet using a consistent format and + prepare it for transmission. + + f. **Transmit Packet** + - Sample a randomized delay from the same distribution family used for + per-hop delays (in Step 3.e.) with an independently chosen mean. + + This delay prevents timing correlation when multiple Sphinx packets are + sent in quick succession. Such bursts may occur when an upstream protocol + fragments a large message, or when several messages are sent close together. + + - After the randomized delay elapses, transmit the serialized packet to + the first hop via a libp2p stream negotiated under the + `"/mix/1.0.0"` protocol identifier. + + Implementations MAY reuse an existing stream to the first hop as + described in [Section 5.5](#55-stream-management-and-multiplexing), if + doing so does not introduce any observable linkability between the + packets. + +Once a Sphinx packet is constructed and transmitted by the initiating node, it is +processed hop-by-hop by the remaining mix nodes in the path. Each node receives +the packet over a libp2p stream negotiated under the `"/mix/1.0.0"` protocol. +The following subsection defines the per-hop packet handling logic expected of +each mix node, depending on whether it acts as an intermediary or an exit. + +### 8.6 Sphinx Packet Handling + +Each mix node MUST implement a handler for incoming data received over +libp2p streams negotiated under the `"/mix/1.0.0"` protocol identifier. +The incoming stream may have been reused by the previous hop, as described +in [Section 5.5](#55-stream-management-and-multiplexing). Implementations +MUST ensure that packet handling remains stateless and unlinkable, +regardless of stream reuse. + +Upon receiving the stream payload, the node MUST interpret it as a Sphinx packet +and process it in one of two roles—intermediary or exit— as defined in +[Section 7.3](#73-sphinx-packet-receiving-and-processing). This section defines +the exact behavior for both roles. + +#### 8.6.1 Shared Preprocessing + +Upon receiving a stream payload over a libp2p stream, the mix node MUST first +deserialize it into a Sphinx packet `(α, β, γ, δ)`. + +The deserialized fields MUST match the sizes defined in [Section 8.5.2](#852-construction-steps) +step 3.e., and the total packet length MUST match the fixed packet size defined in +[Section 8.3.2](#832-payload-size). + +If the stream payload does not match the expected length, it MUST be discarded and +the processing MUST terminate. + +After successful deserialization, the mix node performs the following steps: + +1. **Derive Session Key** + + Let $x \in \mathbb{Z}_q^*$ denote the node's X25519 private key. + Compute the shared secret $s = α^x$. + +2. **Check for Replays** + + - Compute the tag $H(s)$. + - If the tag exists in the node's table of previously seen tags, + discard the packet and terminate processing. + - Otherwise, store the tag in the table. + + The table MAY be flushed when the node rotates its private key. + Implementations SHOULD perform this cleanup securely and automatically. + +3. **Check Header Integrity** + + - Derive the MAC key from the session secret $s$: + + $` + \begin{array}{l} + \mathrm{mac\_key} = + \mathrm{KDF}(\text{"mac\_key"} \mid s) + \end{array} + `$ + + - Verify the integrity of the routing header: + + $` + \begin{array}{l} + γ \stackrel{?}{=} \mathrm{HMAC\text{-}SHA\text{-}256}(\mathrm{mac\_key}, + β) + \end{array} + `$ + + If the check fails, discard the packet and terminate processing. + +4. **Decrypt One Layer of the Routing Header** + + - Derive the routing header AES key and IV from the session secret $s$: + + $` + \begin{array}{l} + β_{\mathrm{aes\_key}} = + \mathrm{KDF}(\text{"aes\_key"} \mid s)\\ + β_{\mathrm{iv}} = + \mathrm{KDF}(\text{"iv"} \mid s) + \end{array} + `$ + + - Decrypt the suitably padded $β$ to obtain the routing block $B$ for this hop: + + $` + \begin{array}{l} + B = \mathrm{AES\text{-}CTR}\bigl(β_{\mathrm{aes\_key}}, + β_{\mathrm{iv}}, β \mid 0_{(t+1)κ} + \bigr) + \end{array} + `$ + + This step removes the filler string appended during header encryption in + [Section 8.5.2](#852-construction-steps) step 3.c. and + yields the plaintext routing information for this hop. + + The routing block $B$ MUST be parsed according to the rules and field layout + defined in [Section 8.6.2](#862-node-role-determination) to determine + whether the current node is an intermediary or the exit. + +5. **Decrypt One Layer of the Payload** + + - Derive the payload AES key and IV from the session secret $s$: + + $` + \begin{array}{l} + δ_{\mathrm{aes\_key}} = + \mathrm{KDF}(\text{"δ\_aes\_key"} \mid s)\\ + δ_{\mathrm{iv}} = + \mathrm{KDF}(\text{"δ\_iv"} \mid s) + \end{array} + `$ + + - Decrypt one layer of the encrypted payload $δ$: + + $` + \begin{array}{l} + δ' = \mathrm{AES\text{-}CTR}\bigl(δ_{\mathrm{aes\_key}}, + δ_{\mathrm{iv}}, δ \bigr) + \end{array} + `$ + + The resulting $δ'$ is the decrypted payload for this hop and MUST be + interpreted depending on the parsed node's role, determined by $B$, as + described in [Section 8.6.2](#862-node-role-determination). + +#### 8.6.2 Node Role Determination + +As described in [Section 8.6.1](#861-shared-preprocessing), the mix node +obtains the routing block $B$ by decrypting one layer of the encrypted +header $β$. + +At this stage, the node MUST determine whether it is an intermediary +or the exit based on the prefix of $B$, in accordance with the construction of +$β_i$ defined in [Section 8.5.2](#852-construction-steps) step 3.c.: + +- If the first $(tκ - 2)$ bytes of $B$ contain a nonzero-encoded + address, immediately followed by a two-byte zero delay, + and then $((t + 1)(r - L) + t + 2)κ$ bytes of all-zero padding, + process the packet as an exit. +- Otherwise, process the packet as an intermediary. + +The following subsections define the precise behavior for each case. + +#### 8.6.3 Intermediary Processing + +Once the node determines its role as an intermediary following the steps in +[Section 8.6.2](#862-node-role-determination), it MUST perform the following +steps to interpret routing block $B$ and decrypted payload $δ'$ obtained in +[Section 8.6.1](#861-shared-preprocessing): + +1. **Parse Routing Block** + + Parse the routing block $B$ according to the $β_i$, $i \neq L - 1$ construction + defined in [Section 8.5.2](#852-construction-steps) step 3.c.: + + - Extract the first $(tκ - 2)$ bytes of $B$ as the next hop address $\mathrm{addr}$ + + $` + \begin{array}{l} + \mathrm{addr} = B_{[0\ldots(tκ - 2) - 1]} + \end{array} + `$ + + - Extract next two bytes as the mean delay $\mathrm{delay}$ + + $` + \begin{array}{l} + \mathrm{delay} = B_{[(tκ - 2)\ldots{tκ} - 1]} + \end{array} + `$ + + - Extract next $κ$ bytes as the next hop MAC $γ'$ + + $` + \begin{array}{l} + γ' = B_{[tκ\ldots(t + 1)κ - 1]} + \end{array} + `$ + + - Extract next $(r(t+1)+1)κ$ bytes as the next hop routing information $β'$ + + $` + \begin{array}{l} + β' = B_{[(t + 1)κ\ldots(r(t +1 ) + t + 2)\kappa - 1]} + \end{array} + `$ + + If parsing fails, discard the packet and terminate processing. + +2. **Update Header Fields** + + Update the header fields according to the construction steps + defined in [Section 8.5.2](#852-construction-steps): + + - Compute the next hop ephemeral public value $α'$, deriving the blinding factor + $b$ from the shared secret $s$ computed in + [Section 8.6.1](#861-shared-preprocessing) step 1. + + $` + \begin{aligned} + b &= H(α\ |\ s) \\ + α' &= α^b + \end{aligned} + `$ + + - Use the $β'$ and $γ'$ extracted in Step 1. as the routing information and + MAC respectively in the outgoing packet. + +3. **Update Payload** + + Use the decrypted payload $δ'$ computed in + [Section 8.6.1](#861-shared-preprocessing) step 5. as the payload in the + outgoing packet. + +4. **Assemble Final Packet** + The final Sphinx packet is structured as defined in + [Section 8.3](#83-packet-component-sizes): + + ```text + α = α' // 32 bytes + β = β' // 576 bytes + γ = γ' // 16 bytes + δ = δ' // 3984 bytes + ``` + + Serialize $α'$ using the same format used in + [Section 8.5.2](#852-construction-steps). The remaining fields are + already fixed-length buffers and do not require further + transformation. + +5. **Transmit Packet** + + - Interpret the $\mathrm{addr}$ and $\mathrm{delay}$ extracted in + Step 1. according to the encoding format used during construction in + [Section 8.5.2](#852-construction-steps) Step 3.c. + + - Sample the actual forwarding delay from the configured delay distribution, + using the decoded mean delay value as the distribution parameter. + + - After the forwarding delay elapses, transmit the serialized packet to + the next hop address via a libp2p stream negotiated under the `"/mix/1.0.0"` + protocol identifier. + + Implementations MAY reuse an existing stream to the next hop as + described in [Section 5.5](#55-stream-management-and-multiplexing), if + doing so does not introduce any observable linkability between the + packets. + +6. **Erase State** + + - After transmission, erase all temporary values securely from memory, + including session keys, decrypted content, and routing metadata. + + - If any error occurs—such as malformed header, invalid delay, or + failed stream transmission—silently discard the packet and do not + send any error response. + +#### 8.6.4 Exit Processing + +Once the node determines its role as an exit following the steps in +[Section 8.6.2](#862-node-role-determination), it MUST perform the following +steps to interpret routing block $B$ and decrypted payload $δ'$ obtained in +[Section 8.6.1](#861-shared-preprocessing): + +1. **Parse Routing Block** + + Parse the routing block $B$ according to the $β_i$, $i = L - 1$ + construction defined in [Section 8.5.2](#852-construction-steps) step 3.c.: + + - Extract first $(tκ - 2)$ bytes of $B$ as the destination address $Δ$ + + $` + \begin{array}{l} + Δ = B_{[0\ldots(tκ - 2) - 1]} + \end{array} + `$ + +2. **Recover Padded Application Message** + + - Verify the decrypted payload $δ'$ computed in + [Section 8.6.1](#861-shared-preprocessing) step 5.: + + $` + \begin{array}{l} + δ'_{[0\ldots{κ} - 1]} \stackrel{?}{=} 0_{κ} + \end{array} + `$ + + If the check fails, discard $δ'$ and terminate processing. + + - Extract rest of the bytes of $δ'$ as the padded application message $m$: + + $` + \begin{array}{l} + m = δ'_{[κ\ldots]},\; \; \; + \text{where notation $X_{[a \ldots]}$ denotes the substring of $X$ + from byte offset $a$ to the end of the string using zero-based indexing.} + \end{array} + `$ + +3. **Extract Application Message** + + Interpret recovered $m$ according to the construction steps + defined in [Section 8.5.2](#852-construction-steps) step 1.: + + - First, unpad $m$ using the deterministic padding scheme defined during + construction. + + - Next, parse the unpadded message deterministically to extract: + + - optional spam protection proof + - zero or more SURBs + - the origin protocol codec + - the serialized application message + + - Parse and deserialize the metadata fields required for spam validation, + SURB extraction, and protocol codec identification, consistent with the + format and extensions applied by the initiator. + The application message itself MUST remain serialized. + + - If parsing fails at any stage, discard $m$ and terminate processing. + +4. **Handoff to Exit Layer** + + - Hand off the serialized application message, the origin protocol codec, and + destination address $Δ$ (extracted in step 1.) to the local Exit layer for + further processing and delivery. + + - The Exit Layer is responsible for establishing a client-only connection and + forwarding the message to the destination. Implementations MAY reuse an + existing stream to the destination, if doing so does not introduce any + observable linkability between forwarded messages. From e742cd519200a7cb0971936bd1dbbeb31397bce5 Mon Sep 17 00:00:00 2001 From: AkshayaMani Date: Wed, 10 Dec 2025 09:45:32 -0500 Subject: [PATCH 2/6] RFC Addition: Section 9 Security Considerations (#194) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR continues work from PR #158 and PR #173, and introduces a new **Section 9: Security Considerations** to the Mix Protocol RFC. It formalizes the protocol’s core guarantees, trust assumptions, and known limitations. ### New Section Added Structured Section 9 with the following subsections: - [x] **9.1 Security Guarantees of the Core Mix Protocol** Defines sender anonymity, metadata protection, and statelessness guarantees. - [x] **9.2 Exit Node Trust Model** Trust assumptions at the final hop: - [x] `9.2.1 Message Delivery and Origin Trust` - [x] `9.2.2 Origin Protocol Trust and Client Role Abuse` - [x] **9.3 Destination as Final Hop** Optional deployment model where the destination operates its own Mix instance to eliminate exit-level trust. - [x] **9.4 Known Protocol Limitations** Clearly outlines out-of-scope threats: - Undetectable node misbehavior - Lack of built-in retries or acknowledgments - No Sybil resistance - Vulnerability to DoS attacks ### Key Improvements - Clearly delineates what the Mix Protocol guarantees and what it leaves to external systems. - Formalizes the exit trust boundary, a key concept for downstream applications. - Introduces an alternative destination participation model. - Enables future discussions around accountability, reliability, and Sybil resistance. --------- Co-authored-by: Prem Chaitanya Prathi --- vac/raw/mix.md | 254 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) diff --git a/vac/raw/mix.md b/vac/raw/mix.md index 4b6198d..17922e3 100644 --- a/vac/raw/mix.md +++ b/vac/raw/mix.md @@ -1751,3 +1751,257 @@ steps to interpret routing block $B$ and decrypted payload $δ'$ obtained in forwarding the message to the destination. Implementations MAY reuse an existing stream to the destination, if doing so does not introduce any observable linkability between forwarded messages. + +## 9. Security Considerations + +This section describes the security guarantees and limitations of the Mix +Protocol. It begins by outlining the anonymity properties provided by the core +protocol when routing messages through the mix network. It then discusses the +trust assumptions required at the edges of the network, particularly at the +final hop. Finally, it presents an alternative trust model for destinations +that support Mix Protocol directly, followed by a summary of broader +limitations and areas that may be addressed in future iterations. + +### 9.1 Security Guarantees of the Core Mix Protocol + +The core Mix Protocol—comprising anonymous routing through a sequence of +mix nodes using Sphinx packets—provides the following security guarantees: + +- **Sender anonymity**: Each message is wrapped in layered encryption and + routed independently, making it unlinkable to the sender even if multiple + mix nodes are colluding. +- **Metadata protection**: All messages are fixed in size and indistinguishable + on the wire. Sphinx packets reveal only the immediate next hop and delay to + each mix node. No intermediate node learns its position in the path or the + total pathlength. +- **Traffic analysis resistance**: Continuous-time mixing with randomized + per-hop delays reduces the risk of timing correlation and input-output + linkage. +- **Per-hop confidentiality and integrity**: Each hop decrypts only its + assigned layer of the Sphinx packet and verifies header integrity via a + per-hop MAC. +- **No long-term state**: All routing is stateless. Mix nodes do not maintain + per-message metadata, reducing the surface for correlation attacks. + +These guarantees hold only within the boundaries of the Mix Protocol. +Additional trust assumptions are introduced at the edges, particularly at the +final hop, where the decrypted message is handed off to the Mix Exit Layer for +delivery to the destination outside the mixnet. The next subsection discusses +these trust assumptions in detail. + +### 9.2 Exit Node Trust Model + +The Mix Protocol ensures strong sender anonymity and metadata protection +between the Mix Entry and Exit layers. However, once a Sphinx packet is +decrypted at the final hop, additional trust assumptions are introduced. +The node processing the final layer of encryption is trusted to forward the +correct message to the destination and return any reply using the provided +reply key. This section outlines the resulting trust boundaries. + +#### 9.2.1 Message Delivery and Origin Trust + +At the final hop, the decrypted Sphinx packet reveals the plaintext message +and destination address. The exit node is then trusted to deliver this message +to the destination application, and—if a reply is expected— +to return the response using the embedded reply key. + +In this model, the exit node becomes a privileged middleman. It has full +visibility into the decrypted payload. Specifically, the exit node could tamper +with either direction of communication without detection: + +- It may alter or drop the forwarded message. +- It may fabricate a reply instead of forwarding the actual response from the + destination. + +This limitation is consistent with the broader mixnet trust model. While +intermediate nodes are constrained by layered encryption, edge nodes +—specifically the initiating and the exit nodes in the path— +are inherently more privileged and operate outside the cryptographic protections +of the mixnet. + +In systems like Tor, such exit-level tampering is mitigated by long-lived circuits +that allow endpoints to negotiate shared session keys (_e.g.,_ via TLS). A +malicious exit cannot forge a valid forward message or response without access to +these session secrets. + +The Mix Protocol, by contrast, is stateless and message-based. Each message is +routed independently, with no persistent circuit or session context. As a +result, endpoints cannot correlate messages, establish session keys, or validate +message origin. That is, the exit remains a necessary point of trust for message +delivery and response handling. + +The next subsection describes a related limitation: the exit’s ability to pose +as a legitimate client to the destination’s origin protocol, and how that +can be abused to bypass application-layer expectations. + +#### 9.2.2 Origin Protocol Trust and Client Role Abuse + +In addition to the message delivery and origin trust assumption, the exit +node also initiates a client-side connection to the origin protocol instance +at the destination. From the destination's perspective, this appears +indistinguishable from a conventional peer connection, and the exit is accepted +as a legitimate peer. + +As a result, any protocol-level safeguards and integrity checks are applied +to the exit node as well. However, since the exit node is not a verifiable peer +and may open fresh connections at will, such protections are limited in their +effectiveness. A malicious exit may repeatedly initiate new connections, send +well-formed fabricated messages and circumvent any peer scoring mechanisms by +reconnecting. These messages are indistinguishable from legitimate peer messages +from the destination’s point of view. + +This class of attack is distinct from basic message tampering. Even if the +message content is well-formed and semantically valid, the exit’s role as an +unaccountable client allows it to bypass application-level assumptions about +peer behavior. This results in protocol misuse, targeted disruption, or +spoofed message injection that the destination cannot attribute. + +Despite these limitations, this model is compatible with legacy protocols and +destinations that do not support the Mix Protocol. It allows applications to +preserve sender anonymity without requiring any participation from the +recipient. + +However, in scenarios that demand stronger end-to-end guarantees—such as +verifiable message delivery, origin authentication, or control over +client access—it may be beneficial for the destination itself to operate +a Mix instance. This alternative model is described in the next subsection. + +### 9.3 Destination as Final Hop + +In some deployments, it may be desirable for the destination node to +participate in the Mix Protocol directly. In this model, the destination +operates its own Mix instance and is selected as the final node in the mix +path. The decrypted message is then delivered by the Mix Exit Layer directly to the +destination's local origin protocol instance, without relying on a separate +exit node. + +From a security standpoint, this model provides end-to-end integrity +guarantees. It removes the trust assumption on an external exit. The message is +decrypted and delivered entirely within the destination node, eliminating the +risk of tampering during the final delivery step. The response, if used, is +also encrypted and returned by the destination itself, avoiding reliance on a +third-party node to apply the reply key. + +This model also avoids client role abuse. Since the Mix Exit Layer delivers the +message locally, the destination need not accept arbitrary inbound connections +from external clients. This removes the risk of an adversarial exit posing as +a peer and injecting protocol-compliant but unauthorized messages. + +This approach does require the destination to support the Mix Protocol. +However, this requirement can be minimized by supporting a lightweight mode in +which the destination only sends and receives messages via Mix, without +participating in message routing for other nodes. This is similar to the model +adopted by Waku, where edge nodes are not required to relay traffic but still +interact with the network. In practice, this tradeoff is often acceptable. + +The core Mix Protocol does not mandate destination participation. However, +implementations MAY support this model as an optional mode for use in +deployments that require stronger end-to-end security guarantees. The discovery +mechanism MAY include a flag to advertise support for routing versus +receive-only participation. Additional details on discovery configurations are +out of scope for this specification. + +This trust model is not required for interoperability, but is recommended +when assessing deployment-specific threat models, especially in protocols that +require message integrity or authenticated replies. + +### 9.4 Known Protocol Limitations + +The Mix Protocol provides strong sender anonymity and metadata protection +guarantees within the mix network. However, it does not address all classes of +network-level disruption or application-layer abuse. This section outlines +known limitations that deployments MUST consider when +evaluating system resilience and reliability. + +#### 9.4.1 Undetectable Node Misbehavior + +The Mix Protocol in its current version does not include mechanisms to detect +or attribute misbehavior by mix nodes. Since Sphinx packets are unlinkable and +routing is stateless, malicious or faulty nodes may delay, drop, or selectively +forward packets without detection. + +This behavior is indistinguishable from benign network failure. There is no +native support for feedback, acknowledgment, or proof-of-relay. As a result, +unreliable nodes cannot be penalized or excluded based on observed reliability. + +Future versions may explore accountability mechanisms. For now, deployments MAY +improve robustness by sending each packet along multiple paths as defined in +[Section X.X], but MUST treat message loss as a possibility. + +#### 9.4.2 No Built-in Retry or Acknowledgment + +The Mix protocol does not support retransmission, delivery acknowledgments, +or automated fallback logic. Each message is sent once and routed +independently through the mixnet. If a message is lost or a node becomes +unavailable, recovery is the responsibility of the top-level application. + +Single-Use Reply Blocks (SURBs) (defined in Section[X.X]) enable destinations to +send responses back to the sender via a fresh mix path. However, SURBs are +optional, and their usage for acknowledgments or retries must be coordinated by +the application. + +Applications using the Mix Protocol MUST treat delivery as probabilistic. To +improve reliability, the sender MAY: + +- Use parallel transmission across `D` disjoint paths. +- Estimate end-to-end delay bounds based on chosen per-hop delays (defined in + [Section 6.2](#62-delay-strategy)), and retry using different paths if + a response is not received within the expected window. + +These strategies MUST be implemented at the origin protocol layer or through +Mix integration logic and are not enforced by the Mix Protocol itself. + +#### 9.4.3 No Sybil Resistance + +The Mix Protocol does not include any built-in defenses against Sybil attacks. +All nodes that support the protocol and are discoverable via peer discovery +are equally eligible for path selection. An adversary that operates a large +number of Sybil nodes may be selected into mix paths more often than expected, +increasing the likelihood of partial or full path compromise. + +In the worst case, if an adversary controls a significant fraction of nodes +(_e.g.,_ one-third of the network), the probability that a given path includes +only adversarial nodes increases sharply. This raises the risk of +deanonymization through end-to-end traffic correlation or timing analysis. + +Deployments concerned with Sybil resistance MAY implement passive defenses +such as minimum path length constraints. More advanced mitigations such as +stake-based participation or resource proofs typically require some form of +trusted setup or blockchain-based coordination. + +Such defenses are out of scope in the current version of the Mix Protocol, +but are critical to ensuring anonymity at scale and may be explored in future +iterations. + +#### 9.4.4 Vulnerability to Denial-of-Service Attacks + +The Mix Protocol does not provide built-in defenses against denial-of-service +(DoS) attacks targeting mix nodes. A malicious mix node may generate +a high volume of valid Sphinx packets to exhaust computational, memory, or +bandwidth resources along random paths through the network. + +This risk stems from the protocol’s stateless and sender-anonymous design. +Mix nodes process each packet independently and cannot distinguish honest users +from attackers. There is no mechanism to attribute packets, limit per-sender +usage, or apply network-wide fairness constraints. + +Application-level defenses—such as PoW, VDFs, and RLNs (defined in +[Section 6.3](#63-spam-protection)) to protect destination endpoints— +do not address abuse _within_ the mixnet. Mix nodes remain vulnerable to +volumetric attacks even when destinations are protected. + +While the Mix Protocol includes safeguards such as layered encryption, per-hop +integrity checks, and fixed-size headers, these primarily defend against +tagging attacks and structurally invalid or malformed traffic. The Sphinx packet +format also enforces a maximum path length $(L \leq r)$, which prevents infinite +loops or excessively long paths being embedded. However, these protections do not +prevent adversaries from injecting large volumes of short, well-formed messages to +exhaust mix node resources. + +DoS protection—such as admission control, rate-limiting, or resource-bound +access—MUST be implemented outside the core protocol. Any such mechanism MUST +preserve sender unlinkability and SHOULD be evaluated carefully to avoid +introducing correlation risks. + +Defending against large-scale DoS attacks is considered a deployment-level +responsibility and is out of scope for this specification. From 7f1df32779d5ff3fa57abc2e71ac2ad1b9662965 Mon Sep 17 00:00:00 2001 From: Prem Chaitanya Prathi Date: Thu, 11 Dec 2025 21:02:15 +0530 Subject: [PATCH 3/6] chore: use sembreaks for easy review and edits (#223) Modified the mix spec to use sembreaks and not break line at charater limits as per https://github.com/vacp2p/rfc-index/pull/194#pullrequestreview-3562274262 --- vac/raw/mix.md | 1688 +++++++++++++++--------------------------------- 1 file changed, 512 insertions(+), 1176 deletions(-) diff --git a/vac/raw/mix.md b/vac/raw/mix.md index 17922e3..e10a255 100644 --- a/vac/raw/mix.md +++ b/vac/raw/mix.md @@ -4,768 +4,424 @@ name: Libp2p Mix Protocol status: raw category: Standards Track tags: -editor: Akshaya Mani -contributors: Daniel Kaiser +editor: Prem Prathi +contributors: Akshaya Mani , Daniel Kaiser --- ## Abstract -The Mix Protocol defines a decentralized anonymous message routing layer for -libp2p networks. -It enables sender anonymity by routing each message through a decentralized mix -overlay network -composed of participating libp2p nodes, known as mix nodes. Each message is -routed independently -in a stateless manner, allowing other libp2p protocols to selectively anonymize -messages without -modifying their core protocol behavior. +The Mix Protocol defines a decentralized anonymous message routing layer for libp2p networks. +It enables sender anonymity by routing each message through a decentralized mix overlay network composed of participating libp2p nodes, known as mix nodes. +Each message is routed independently in a stateless manner, allowing other libp2p protocols to selectively anonymize messages without modifying their core protocol behavior. ## 1. Introduction -The Mix Protocol is a custom libp2p protocol that defines a message-layer -routing abstraction -designed to provide sender anonymity in peer-to-peer systems built on the libp2p -stack. -It addresses the absence of native anonymity primitives in libp2p by offering a -modular, -content-agnostic protocol that other libp2p protocols can invoke when anonymity -is required. +The Mix Protocol is a custom libp2p protocol that defines a message-layer routing abstraction designed to provide sender anonymity in peer-to-peer systems built on the libp2p stack. +It addresses the absence of native anonymity primitives in libp2p by offering a modular, content-agnostic protocol that other libp2p protocols can invoke when anonymity is required. -This document describes the design, behavior, and integration of the Mix -Protocol within the -libp2p architecture. Rather than replacing or modifying existing libp2p -protocols, the Mix Protocol -complements them by operating independently of connection state and protocol -negotiation. -It is intended to be used as an optional anonymity layer that can be selectively -applied on a -per-message basis. +This document describes the design, behavior, and integration of the Mix Protocol within the libp2p architecture. +Rather than replacing or modifying existing libp2p protocols, the Mix Protocol complements them by operating independently of connection state and protocol negotiation. +It is intended to be used as an optional anonymity layer that can be selectively applied on a per-message basis. -Integration with other libp2p protocols is handled through external interface -components—the Mix Entry -and Exit layers—which mediate between these protocols and the Mix Protocol -instances. -These components allow applications to defer anonymity concerns to the Mix layer -without altering -their native semantics or transport assumptions. +Integration with other libp2p protocols is handled through external interface components—the Mix Entry and Exit layers—which mediate between these protocols and the Mix Protocol instances. +These components allow applications to defer anonymity concerns to the Mix layer without altering their native semantics or transport assumptions. -The rest of this document describes the motivation for the protocol, defines -relevant terminology, -presents the protocol architecture, and explains how the Mix Protocol -interoperates with the broader -libp2p protocol ecosystem. +The rest of this document describes the motivation for the protocol, defines relevant terminology, presents the protocol architecture, and explains how the Mix Protocol interoperates with the broader libp2p protocol ecosystem. ## 2. Terminology -The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, -“SHOULD NOT”, “RECOMMENDED”, -“MAY”, and “OPTIONAL” in this document are to be interpreted as described in -[RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119). +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119). The following terms are used throughout this specification: - **Origin Protocol** -A libp2p protocol (_e.g.,_ Ping, GossipSub) that generates and receives the -actual message payload. -The origin protocol MUST decide on a per-message basis whether to route the -message through the Mix Protocol -or not. + A libp2p protocol (_e.g.,_ Ping, GossipSub) that generates and receives the actual message payload. + The origin protocol MUST decide on a per-message basis whether to route the message through the Mix Protocol or not. - **Mix Node** -A libp2p node that supports the Mix Protocol and participates in the mix -network. -A mix node initiates anonymous routing when invoked with a message. -It also receives and processes Sphinx packets when selected as a hop in a mix -path. + A libp2p node that supports the Mix Protocol and participates in the mix network. + A mix node initiates anonymous routing when invoked with a message. + It also receives and processes Sphinx packets when selected as a hop in a mix path. - **Mix Path** -A non-repeating sequence of mix nodes through which a Sphinx packet is routed -across the mix network. + A non-repeating sequence of mix nodes through which a Sphinx packet is routed across the mix network. - **Mixify** -A per-message flag set by the origin protocol to indicate that a message should -be routed using -the Mix Protocol or not. -Only messages with mixify set are forwarded to the Mix Entry Layer. -Other messages SHOULD be routed using the origin protocol’s default behavior. -The phrases 'messages to be mixified', 'to mixify a message' and related -variants are used -informally throughout this document to refer to messages that either have the -`mixify` flag set -or are selected to have it set. + A per-message flag set by the origin protocol to indicate that a message should be routed using the Mix Protocol or not. + Only messages with mixify set are forwarded to the Mix Entry Layer. Other messages SHOULD be routed using the origin protocol's default behavior. + The phrases 'messages to be mixified', 'to mixify a message' and related variants are used informally throughout this document to refer to messages that either have the `mixify` flag set or are selected to have it set. - **Mix Entry Layer** -A component that receives messages to be _mixified_ from an origin protocol and -forwards them to the -local Mix Protocol instance. -The Entry Layer is external to the Mix Protocol. + A component that receives messages to be _mixified_ from an origin protocol and forwards them to the local Mix Protocol instance. + The Entry Layer is external to the Mix Protocol. - **Mix Exit Layer** -A component that receives decrypted messages from a Mix Protocol instance and -delivers them -to the appropriate origin protocol instance at the destination. -Like the Entry Layer, it is external to the Mix Protocol. + A component that receives decrypted messages from a Mix Protocol instance and delivers them to the appropriate origin protocol instance at the destination. + Like the Entry Layer, it is external to the Mix Protocol. - **Mixnet or Mix Network** -A decentralized overlay network formed by all nodes that support the Mix -Protocol. -It operates independently of libp2p’s protocol-level routing and origin protocol -behavior. + A decentralized overlay network formed by all nodes that support the Mix Protocol. + It operates independently of libp2p's protocol-level routing and origin protocol behavior. - **Sphinx Packet** -A cryptographic packet format used by the Mix Protocol to encapsulate messages. -It uses layered encryption to hide routing information and protect message -contents as packets are forwarded hop-by-hop. -Sphinx packets are fixed-size and indistinguishable from one another, providing -unlinkability and metadata protection. + A cryptographic packet format used by the Mix Protocol to encapsulate messages. + It uses layered encryption to hide routing information and protect message contents as packets are forwarded hop-by-hop. + Sphinx packets are fixed-size and indistinguishable from one another, providing unlinkability and metadata protection. - **Initialization Vector (IV)** - A fixed-length input used to initialize block ciphers to add randomness to the - encryption process. It ensures that encrypting the same plaintext with the same - key produces different ciphertexts. The IV is not secret but must be unique for - each encryption. + A fixed-length input used to initialize block ciphers to add randomness to the encryption process. + It ensures that encrypting the same plaintext with the same key produces different ciphertexts. + The IV is not secret but must be unique for each encryption. - **Single-Use Reply Block (SURB)** -A pre-computed Sphinx header that encodes a return path back to the sender. -SURBs are generated by the sender and included in the Sphinx packet sent to the recipient. -It enables the recipient to send anonymous replies, -without learning the sender’s identity, the return path, or the forwarding delays. + A pre-computed Sphinx header that encodes a return path back to the sender. + SURBs are generated by the sender and included in the Sphinx packet sent to the recipient. + It enables the recipient to send anonymous replies, without learning the sender's identity, the return path, or the forwarding delays. ## 3. Motivation and Background -libp2p enables modular peer-to-peer applications, but it lacks built-in support -for sender anonymity. -Most protocols expose persistent peer identifiers, transport metadata, or -traffic patterns that -can be exploited to deanonymize users through passive observation or -correlation. +libp2p enables modular peer-to-peer applications, but it lacks built-in support for sender anonymity. +Most protocols expose persistent peer identifiers, transport metadata, or traffic patterns that can be exploited to deanonymize users through passive observation or correlation. -While libp2p supports NAT traversal mechanisms such as Circuit Relay, these -focus on connectivity -rather than anonymity. Relays may learn peer identities during stream setup and -can observe traffic -timing and volume, offering no protection against metadata analysis. +While libp2p supports NAT traversal mechanisms such as Circuit Relay, these focus on connectivity rather than anonymity. +Relays may learn peer identities during stream setup and can observe traffic timing and volume, offering no protection against metadata analysis. -libp2p also supports a Tor transport for network-level anonymity, tunneling -traffic through long-lived, -encrypted circuits. However, Tor relies on session persistence and is ill-suited -for protocols -requiring per-message unlinkability. +libp2p also supports a Tor transport for network-level anonymity, tunneling traffic through long-lived, encrypted circuits. +However, Tor relies on session persistence and is ill-suited for protocols requiring per-message unlinkability. -The Mix Protocol addresses this gap with a decentralized message routing layer -based on classical -mix network principles. It applies layered encryption and per-hop delays to -obscure both routing paths -and timing correlations. Each message is routed independently, providing -resistance to traffic analysis -and protection against metadata leakage +The Mix Protocol addresses this gap with a decentralized message routing layer based on classical mix network principles. +It applies layered encryption and per-hop delays to obscure both routing paths and timing correlations. +Each message is routed independently, providing resistance to traffic analysis and protection against metadata leakage -By decoupling anonymity from connection state and transport negotiation, the Mix -Protocol offers -a modular privacy abstraction that existing libp2p protocols can adopt without -altering their -core behavior. +By decoupling anonymity from connection state and transport negotiation, the Mix Protocol offers a modular privacy abstraction that existing libp2p protocols can adopt without altering their core behavior. -To better illustrate the differences in design goals and threat models, the -following subsection contrasts -the Mix Protocol with Tor, a widely known anonymity system. +To better illustrate the differences in design goals and threat models, the following subsection contrasts the Mix Protocol with Tor, a widely known anonymity system. ### 3.1 Comparison with Tor The Mix Protocol differs fundamentally from Tor in several ways: -- **Unlinkability**: In the Mix Protocol, there is no direct connection between -source and destination. -Each message is routed independently, eliminating correlation through persistent -circuits. +- **Unlinkability**: In the Mix Protocol, there is no direct connection between source and destination. + Each message is routed independently, eliminating correlation through persistent circuits. -- **Delay-based mixing**: Mix nodes introduce randomized delays (e.g., from an -exponential distribution) -before forwarding messages, making timing correlation significantly harder. +- **Delay-based mixing**: Mix nodes introduce randomized delays (e.g., from an exponential distribution) before forwarding messages, making timing correlation significantly harder. -- **High-latency focus**: Tor prioritizes low-latency communication for -interactive web traffic, -whereas the Mix Protocol is designed for scenarios where higher latency is -acceptable -in exchange for stronger anonymity. +- **High-latency focus**: Tor prioritizes low-latency communication for interactive web traffic, whereas the Mix Protocol is designed for scenarios where higher latency is acceptable in exchange for stronger anonymity. -- **Message-based design**: Each message in the Mix Protocol is self-contained -and independently routed. -No sessions or state are maintained between messages. +- **Message-based design**: Each message in the Mix Protocol is self-contained and independently routed. + No sessions or state are maintained between messages. -- **Resistance to endpoint attacks**: The Mix Protocol is less susceptible to -certain endpoint-level attacks, -such as traffic volume correlation or targeted probing, since messages are -delayed, reordered, and unlinkable at each hop. +- **Resistance to endpoint attacks**: The Mix Protocol is less susceptible to certain endpoint-level attacks, such as traffic volume correlation or targeted probing, since messages are delayed, reordered, and unlinkable at each hop. -To understand the underlying anonymity properties of the Mix Protocol, we next -describe the core components of a mix network. +To understand the underlying anonymity properties of the Mix Protocol, we next describe the core components of a mix network. ## 4. Mixing Strategy and Packet Format -The Mix Protocol relies on two core design elements to achieve sender -unlinkability and metadata -protection: a mixing strategy and a cryptographically secure mix packet -format. +The Mix Protocol relies on two core design elements to achieve sender unlinkability and metadata protection: +a mixing strategy and a cryptographically secure mix packet format. ### 4.1 Mixing Strategy -A mixing strategy defines how mix nodes delay and reorder incoming packets to -resist timing -correlation and input-output linkage. Two commonly used approaches are -batch-based mixing and -continuous-time mixing. +A mixing strategy defines how mix nodes delay and reorder incoming packets to resist timing correlation and input-output linkage. +Two commonly used approaches are batch-based mixing and continuous-time mixing. -In batching-based mixing, each mix node collects incoming packets over a fixed -or adaptive -interval, shuffles them, and forwards them in a batch. While this provides some -unlinkability, -it introduces high latency, requires synchronized flushing rounds, and may -result in bursty -output traffic. Anonymity is bounded by the batch size, and performance may -degrade under variable -message rates. +In batching-based mixing, each mix node collects incoming packets over a fixed or adaptive interval, shuffles them, and forwards them in a batch. +While this provides some unlinkability, it introduces high latency, requires synchronized flushing rounds, and may result in bursty output traffic. +Anonymity is bounded by the batch size, and performance may degrade under variable message rates. -The Mix Protocol instead uses continuous-time mixing, where each mix node -applies a randomized -delay to every incoming packet, typically drawn from an exponential -distribution. This enables -theoretically unbounded anonymity sets, since any packet may, with non-zero -probability, -be delayed arbitrarily long. In practice, the distribution is truncated once the -probability -of delay falls below a negligible threshold. Continuous-time mixing also offers -improved -bandwidth utilization and smoother output traffic compared to batching-based -approaches. +The Mix Protocol instead uses continuous-time mixing, where each mix node applies a randomized delay to every incoming packet, typically drawn from an exponential distribution. +This enables theoretically unbounded anonymity sets, since any packet may, with non-zero probability, be delayed arbitrarily long. +In practice, the distribution is truncated once the probability of delay falls below a negligible threshold. +Continuous-time mixing also offers improved bandwidth utilization and smoother output traffic compared to batching-based approaches. -To make continuous-time mixing tunable and predictable, the sender MUST select -the mean delay -for each hop and encode it into the Sphinx packet header. This allows top-level -applications -to balance latency and anonymity according to their requirements. +To make continuous-time mixing tunable and predictable, the sender MUST select the mean delay for each hop and encode it into the Sphinx packet header. +This allows top-level applications to balance latency and anonymity according to their requirements. ### 4.2 Mix Packet Format -A mix packet format defines how messages are encapsulated and routed through a -mix network. -It must ensure unlinkability between incoming and outgoing packets, prevent -metadata leakage -(e.g., path length, hop position, or payload size), and support uniform -processing by mix nodes -regardless of direction or content. +A mix packet format defines how messages are encapsulated and routed through a mix network. +It must ensure unlinkability between incoming and outgoing packets, prevent metadata leakage (e.g., path length, hop position, or payload size), and support uniform processing by mix nodes regardless of direction or content. -The Mix Protocol uses [Sphinx -packets](https://cypherpunks.ca/~iang/pubs/Sphinx_Oakland09.pdf) -to meet these goals. -Each message is encrypted in layers corresponding to the selected mix path. As a -packet traverses -the network, each mix node removes one encryption layer to obtain the next hop -and delay, -while the remaining payload remains encrypted and indistinguishable. +The Mix Protocol uses [Sphinx packets](https://cypherpunks.ca/~iang/pubs/Sphinx_Oakland09.pdf) to meet these goals. +Each message is encrypted in layers corresponding to the selected mix path. +As a packet traverses the network, each mix node removes one encryption layer to obtain the next hop and delay, while the remaining payload remains encrypted and indistinguishable. -Sphinx packets are fixed in size and bit-wise unlinkable. This ensures that they -appear identical -on the wire regardless of payload, direction, or route length, reducing -opportunities for correlation -based on packet size or format. Even mix nodes learn only the immediate routing -information -and the delay to be applied. They do not learn their position in the path or the -total number of hops. +Sphinx packets are fixed in size and bit-wise unlinkable. +This ensures that they appear identical on the wire regardless of payload, direction, or route length, reducing opportunities for correlation based on packet size or format. +Even mix nodes learn only the immediate routing information and the delay to be applied. +They do not learn their position in the path or the total number of hops. -The packet format is resistant to tagging and replay attacks and is compact and -efficient to -process. Sphinx packets also include per-hop integrity checks and enforces a -maximum path length. -Together with a constant-size header and payload, this provides bounded -protection -against -endless routing and malformed packet propagation. +The packet format is resistant to tagging and replay attacks and is compact and efficient to process. +Sphinx packets also include per-hop integrity checks and enforces a maximum path length. +Together with a constant-size header and payload, this provides bounded protection against endless routing and malformed packet propagation. -It also supports anonymous and indistinguishable reply messages through -[Single-Use Reply Blocks -(SURBs)](https://cypherpunks.ca/~iang/pubs/Sphinx_Oakland09.pdf), -although reply support is not implemented yet. +It also supports anonymous and indistinguishable reply messages through [Single-Use Reply Blocks (SURBs)](https://cypherpunks.ca/~iang/pubs/Sphinx_Oakland09.pdf), although reply support is not implemented yet. -A complete specification of the Sphinx packet structure and fields is provided -in [Section 6]. +A complete specification of the Sphinx packet structure and fields is provided in [Section 6]. ## 5. Protocol Overview -The Mix Protocol defines a decentralized, message-based routing layer that -provides sender anonymity -within the libp2p framework. +The Mix Protocol defines a decentralized, message-based routing layer that provides sender anonymity within the libp2p framework. +It is agnostic to message content and semantics. +Each message is treated as an opaque payload, wrapped into a [Sphinx packet](https://cypherpunks.ca/~iang/pubs/Sphinx_Oakland09.pdf) and routed independently through a randomly selected mix path. +Along the path, each mix node removes one layer of encryption, adds a randomized delay, and forwards the packet to the next hop. +This combination of layered encryption and per-hop delay provides resistance to traffic analysis and enables message-level unlinkability. -It is agnostic to message content and semantics. Each message is treated as an -opaque payload, -wrapped into a [Sphinx -packet](https://cypherpunks.ca/~iang/pubs/Sphinx_Oakland09.pdf) and routed -independently through a randomly selected mix path. Along the path, each mix -node removes one layer -of encryption, adds a randomized delay, and forwards the packet to the next hop. -This combination of -layered encryption and per-hop delay provides resistance to traffic analysis and -enables message-level -unlinkability. +Unlike typical custom libp2p protocols, the Mix Protocol is stateless—it does not establish persistent streams, negotiate protocols, or maintain sessions. +Each message is self-contained and routed independently. -Unlike typical custom libp2p protocols, the Mix Protocol is stateless—it -does not establish -persistent streams, negotiate protocols, or maintain sessions. Each message is -self-contained -and routed independently. +The Mix Protocol sits above the transport layer and below the protocol layer in the libp2p stack. +It provides a modular anonymity layer that other libp2p protocols MAY invoke selectively on a per-message basis. -The Mix Protocol sits above the transport layer and below the protocol layer in -the libp2p stack. -It provides a modular anonymity layer that other libp2p protocols MAY invoke -selectively on a -per-message basis. +Integration with other libp2p protocols is handled through external components that mediate between the origin protocol and the Mix Protocol instances. +This enables selective anonymous routing without modifying protocol semantics or internal behavior. -Integration with other libp2p protocols is handled through external components -that mediate -between the origin protocol and the Mix Protocol instances. This enables -selective anonymous routing -without modifying protocol semantics or internal behavior. - -The following subsections describe how the Mix Protocol integrates with origin -protocols via -the Mix Entry and Exit layers, how per-message anonymity is controlled through -the `mixify` flag, -the rationale for defining Mix as a protocol rather than a transport, and the -end-to-end message -interaction flow. +The following subsections describe how the Mix Protocol integrates with origin protocols via the Mix Entry and Exit layers, how per-message anonymity is controlled through the `mixify` flag, the rationale for defining Mix as a protocol rather than a transport, and the end-to-end message interaction flow. ### 5.1 Integration with Origin Protocols -libp2p protocols that wish to anonymize messages MUST do so by integrating with -the Mix Protocol -via the Mix Entry and Exit layers. +libp2p protocols that wish to anonymize messages MUST do so by integrating with the Mix Protocol via the Mix Entry and Exit layers. -- The **Mix Entry Layer** receives messages to be _mixified_ from an origin -protocol and forwards them -to the local Mix Protocol instance. +- The **Mix Entry Layer** receives messages to be _mixified_ from an origin protocol and forwards them to the local Mix Protocol instance. -- The **Mix Exit Layer** receives the final decrypted message from a Mix -Protocol instance and -forwards it to the appropriate origin protocol instance at the destination over -a client-only connection. +- The **Mix Exit Layer** receives the final decrypted message from a Mix Protocol instance and forwards it to the appropriate origin protocol instance at the destination over a client-only connection. -This integration is external to the Mix Protocol and is not handled by mix nodes -themselves. +This integration is external to the Mix Protocol and is not handled by mix nodes themselves. ### 5.2 Mixify Option -Some origin protocols may require selective anonymity, choosing to anonymize -_only_ certain messages -based on their content, context, or destination. For example, a protocol may -only anonymize messages -containing sensitive metadata while delivering others directly to optimize -performance. +Some origin protocols may require selective anonymity, choosing to anonymize _only_ certain messages based on their content, context, or destination. +For example, a protocol may only anonymize messages containing sensitive metadata while delivering others directly to optimize performance. -To support this, origin protocols MAY implement a per-message `mixify` flag that -indicates whether a message should be routed using the Mix Protocol. +To support this, origin protocols MAY implement a per-message `mixify` flag that indicates whether a message should be routed using the Mix Protocol. -- If the flag is set, the message MUST be handed off to the Mix Entry Layer for -anonymous routing. -- If the flag is not set, the message SHOULD be routed using the origin -protocol’s default mechanism. +- If the flag is set, the message MUST be handed off to the Mix Entry Layer for anonymous routing. +- If the flag is not set, the message SHOULD be routed using the origin protocol's default mechanism. -This design enables protocols to invoke the Mix Protocol only for selected -messages, providing fine-grained control over privacy and performance -trade-offs. +This design enables protocols to invoke the Mix Protocol only for selected messages, providing fine-grained control over privacy and performance trade-offs. ### 5.3 Why a Protocol, Not a Transport -The Mix Protocol is specified as a custom libp2p protocol rather than a -transport to support -selective anonymity while remaining compatible with libp2p’s architecture. +The Mix Protocol is specified as a custom libp2p protocol rather than a transport to support selective anonymity while remaining compatible with libp2p's architecture. -As noted in [Section 5.2](#52-mixify-option), origin protocols may anonymize -only specific messages -based on content or context. Supporting such selective behavior requires -invoking Mix on a per-message basis. +As noted in [Section 5.2](#52-mixify-option), origin protocols may anonymize only specific messages based on content or context. +Supporting such selective behavior requires invoking Mix on a per-message basis. -libp2p transports, however, are negotiated per peer connection and apply -globally to all messages -exchanged between two peers. Enabling selective anonymity at the transport layer -would -therefore require -changes to libp2p’s core transport semantics. +libp2p transports, however, are negotiated per peer connection and apply globally to all messages exchanged between two peers. +Enabling selective anonymity at the transport layer would therefore require changes to libp2p's core transport semantics. Defining Mix as a protocol avoids these constraints and offers several benefits: - Supports selective invocation on a per-message basis. -- Works atop existing secure transports (_e.g.,_ QUIC, TLS) without requiring -changes to the transport stack. -- Preserves a stateless, content-agnostic model focused on anonymous message -routing. +- Works atop existing secure transports (_e.g.,_ QUIC, TLS) without requiring changes to the transport stack. +- Preserves a stateless, content-agnostic model focused on anonymous message routing. - Integrates seamlessly with origin protocols via the Mix Entry and Exit layers. -This design preserves the modularity of the libp2p stack and allows Mix to be -adopted without altering existing transport or protocol behavior. +This design preserves the modularity of the libp2p stack and allows Mix to be adopted without altering existing transport or protocol behavior. ### 5.4 Protocol Interaction Flow -A typical end-to-end Mix Protocol flow consists of the following three -conceptual phases. -Only the second phase—the anonymous routing performed by mix -nodes—is part of the core -Mix Protocol. The entry-side and exit-side integration steps are handled -externally by the Mix Entry -and Exit layers. +A typical end-to-end Mix Protocol flow consists of the following three conceptual phases. +Only the second phase—the anonymous routing performed by mix nodes—is part of the core Mix Protocol. +The entry-side and exit-side integration steps are handled externally by the Mix Entry and Exit layers. 1. **Entry-side Integration (Mix Entry Layer):** - The origin protocol generates a message and sets the `mixify` flag. - - The message is passed to the Mix Entry Layer, which invokes the local Mix -Protocol instance with -the message, destination, and origin protocol codec as input. + - The message is passed to the Mix Entry Layer, which invokes the local Mix Protocol instance with the message, destination, and origin protocol codec as input. 2. **Anonymous Routing (Core Mix Protocol):** - - The Mix Protocol instance wraps the message in a Sphinx packet and selects a -random mix path. + - The Mix Protocol instance wraps the message in a Sphinx packet and selects a random mix path. - Each mix node along the path: - Processes the Sphinx packet by removing one encryption layer. - Applies a delay and forwards the packet to the next hop. - - The final node in the path (exit node) decrypts the final layer, extracting -the original plaintext message, destination, and origin protocol codec. + - The final node in the path (exit node) decrypts the final layer, extracting the original plaintext message, destination, and origin protocol codec. 3. **Exit-side Integration (Mix Exit Layer):** - - The Mix Exit Layer receives the plaintext message, destination, and origin -protocol codec. - - It routes the message to the destination origin protocol instance using a -client-only connection. + - The Mix Exit Layer receives the plaintext message, destination, and origin protocol codec. + - It routes the message to the destination origin protocol instance using a client-only connection. -The destination node does not need to support the Mix Protocol to receive or -respond -to anonymous messages. +The destination node does not need to support the Mix Protocol to receive or respond to anonymous messages. -The behavior described above represents the core Mix Protocol. In addition, the -protocol -supports a set of pluggable components that extend its functionality. These -components cover -areas such as node discovery, delay strategy, spam resistance, cover traffic -generation, -and incentivization. Some are REQUIRED for interoperability; others are OPTIONAL -or deployment-specific. +The behavior described above represents the core Mix Protocol. +In addition, the protocol supports a set of pluggable components that extend its functionality. +These components cover areas such as node discovery, delay strategy, spam resistance, cover traffic generation, and incentivization. +Some are REQUIRED for interoperability; others are OPTIONAL or deployment-specific. The next section describes each component. ### 5.5 Stream Management and Multiplexing -Each Mix Protocol message is routed independently, and forwarding it to the next -hop requires -opening a new libp2p stream using the Mix Protocol. This applies to both the -initial Sphinx packet -transmission and each hop along the mix path. +Each Mix Protocol message is routed independently, and forwarding it to the next hop requires opening a new libp2p stream using the Mix Protocol. +This applies to both the initial Sphinx packet transmission and each hop along the mix path. -In high-throughput environments (_e.g._, messaging systems with continuous -anonymous traffic), -mix nodes may frequently communicate with a subset of mix nodes. Opening a new -stream for each -Sphinx packet in such scenarios can incur performance costs, as each stream -setup requires a -multistream handshake for protocol negotiation. +In high-throughput environments (_e.g._, messaging systems with continuous anonymous traffic), mix nodes may frequently communicate with a subset of mix nodes. +Opening a new stream for each Sphinx packet in such scenarios can incur performance costs, as each stream setup requires a multistream handshake for protocol negotiation. -While libp2p supports multiplexing multiple streams over a single transport -connection using -stream muxers such as mplex and yamux, it does not natively support reusing the -same stream over multiple -message transmissions. However, stream reuse may be desirable in the mixnet -setting to reduce overhead -and avoid hitting per protocol stream limits between peers. +While libp2p supports multiplexing multiple streams over a single transport connection using stream muxers such as mplex and yamux, it does not natively support reusing the same stream over multiple message transmissions. +However, stream reuse may be desirable in the mixnet setting to reduce overhead and avoid hitting per protocol stream limits between peers. -The lifecycle of streams, including their reuse, eviction, or pooling strategy, -is outside the -scope of this specification. It SHOULD be handled by the libp2p host, connection -manager, or -transport stack. +The lifecycle of streams, including their reuse, eviction, or pooling strategy, is outside the scope of this specification. +It SHOULD be handled by the libp2p host, connection manager, or transport stack. -Mix Protocol implementations MUST NOT assume persistent stream availability and -SHOULD gracefully -fall back to opening a new stream when reuse is not possible. +Mix Protocol implementations MUST NOT assume persistent stream availability and SHOULD gracefully fall back to opening a new stream when reuse is not possible. ## 6. Pluggable Components -Pluggable components define functionality that extends or configures the -behavior of the Mix Protocol -beyond its core message routing logic. Each component in this section falls into -one of two categories: +Pluggable components define functionality that extends or configures the behavior of the Mix Protocol beyond its core message routing logic. +Each component in this section falls into one of two categories: -- Required for interoperability and path construction (_e.g.,_ discovery, delay -strategy). -- Optional or deployment-specific (_e.g.,_ spam protection, cover traffic, -incentivization). +- Required for interoperability and path construction (_e.g.,_ discovery, delay strategy). +- Optional or deployment-specific (_e.g.,_ spam protection, cover traffic, incentivization). The following subsections describe the role and expected behavior of each. ### 6.1 Discovery -The Mix Protocol does not mandate a specific peer discovery mechanism. However, -nodes participating in -the mixnet MUST be discoverable so that other nodes can construct routing paths -that include them. +The Mix Protocol does not mandate a specific peer discovery mechanism. +However, nodes participating in the mixnet MUST be discoverable so that other nodes can construct routing paths that include them. -To enable this, regardless of the discovery mechanism used, each mix node MUST -make the following -information available to peers: +To enable this, regardless of the discovery mechanism used, each mix node MUST make the following information available to peers: - Indicate Mix Protocol support (_e.g.,_ using a `mix` field or bit). - Its X25519 public key for Sphinx encryption. -- One or more routable libp2p multiaddresses that identify the mix node’s own -network endpoints. +- One or more routable libp2p multiaddresses that identify the mix node's own network endpoints. -To support sender anonymity at scale, discovery mechanism SHOULD support -_unbiased random sampling_ -from the set of live mix nodes. This enables diverse path construction and -reduces exposure to -adversarial routing bias. +To support sender anonymity at scale, discovery mechanism SHOULD support _unbiased random sampling_ from the set of live mix nodes. +This enables diverse path construction and reduces exposure to adversarial routing bias. -While no existing mechanism provides unbiased sampling by default, -[Waku’s ambient discovery](https://rfc.vac.dev/waku/standards/core/33/discv5/) -—an extension -over [Discv5](https://github.com/ethereum/devp2p/blob/master/discv5/discv5.md) -—demonstrates -an approximate solution. It combines topic-based capability advertisement with -periodic -peer sampling. A similar strategy could potentially be adapted for the Mix -Protocol. +While no existing mechanism provides unbiased sampling by default, [Waku's ambient discovery](https://rfc.vac.dev/waku/standards/core/33/discv5/)—an extension over [Discv5](https://github.com/ethereum/devp2p/blob/master/discv5/discv5.md)—demonstrates an approximate solution. +It combines topic-based capability advertisement with periodic peer sampling. +A similar strategy could potentially be adapted for the Mix Protocol. -A more robust solution would involve integrating capability-aware discovery -directly into the -libp2p stack, such as through extensions to `libp2p-kaddht`. This would enable -direct lookup of -mix nodes based on protocol support and eliminate reliance on external -mechanisms such as Discv5. -Such an enhancement remains exploratory and is outside the scope of this -specification. +A more robust solution would involve integrating capability-aware discovery directly into the libp2p stack, such as through extensions to `libp2p-kaddht`. +This would enable direct lookup of mix nodes based on protocol support and eliminate reliance on external mechanisms such as Discv5. +Such an enhancement remains exploratory and is outside the scope of this specification. -Regardless of the mechanism, the goal is to ensure mix nodes are discoverable -and that path selection -is resistant to bias and node churn. +Regardless of the mechanism, the goal is to ensure mix nodes are discoverable and that path selection is resistant to bias and node churn. ### 6.2 Delay Strategy -The Mix Protocol uses per-hop delay as a core mechanism for achieving timing -unlinkability. -For each hop in the mix path, the sender MUST specify a mean delay value, which -is embedded in -the Sphinx packet header. The mix node at each hop uses this value to sample a -randomized delay -before forwarding the packet. +The Mix Protocol uses per-hop delay as a core mechanism for achieving timing unlinkability. +For each hop in the mix path, the sender MUST specify a mean delay value, which is embedded in the Sphinx packet header. +The mix node at each hop uses this value to sample a randomized delay before forwarding the packet. -By default, delays are sampled from an exponential distribution. This supports -continuous-time mixing, -produces smooth output traffic, and enables tunable trade-offs between latency -and anonymity. -Importantly, it allows for unbounded anonymity sets: each packet may, with -non-zero probability, -be delayed arbitrarily long. +By default, delays are sampled from an exponential distribution. +This supports continuous-time mixing, produces smooth output traffic, and enables tunable trade-offs between latency and anonymity. +Importantly, it allows for unbounded anonymity sets: each packet may, with non-zero probability, be delayed arbitrarily long. -The delay strategy is considered pluggable, and other distributions MAY be used -to match -application-specific anonymity or performance requirements. However, any delay -strategy -MUST ensure that: +The delay strategy is considered pluggable, and other distributions MAY be used to match application-specific anonymity or performance requirements. +However, any delay strategy MUST ensure that: - Delays are sampled independently at each hop. -- Delay sampling introduces sufficient variability to obscure timing correlation -between packet -arrival and forwarding across multiple hops. +- Delay sampling introduces sufficient variability to obscure timing correlation between packet arrival and forwarding across multiple hops. -Strategies that produce deterministic or tightly clustered output delays are NOT -RECOMMENDED, -as they increase the risk of timing correlation. Delay strategies SHOULD -introduce enough uncertainty -to prevent adversaries from linking packet arrival and departure times, even -when monitoring -multiple hops concurrently. +Strategies that produce deterministic or tightly clustered output delays are NOT RECOMMENDED, as they increase the risk of timing correlation. +Delay strategies SHOULD introduce enough uncertainty to prevent adversaries from linking packet arrival and departure times, even when monitoring multiple hops concurrently. ### 6.3 Spam Protection -The Mix Protocol supports optional spam protection mechanisms to defend -recipients against -abusive or unsolicited traffic. These mechanisms are applied at the exit node, -which is the -final node in the mix path before the message is delivered to its destination -via the respective -libp2p protocol. +The Mix Protocol supports optional spam protection mechanisms to defend recipients against abusive or unsolicited traffic. +These mechanisms are applied at the exit node, which is the final node in the mix path before the message is delivered to its destination via the respective libp2p protocol. -Exit nodes that enforce spam protection MUST validate the attached proof before -forwarding -the message. If validation fails, the message MUST be discarded. +Exit nodes that enforce spam protection MUST validate the attached proof before forwarding the message. +If validation fails, the message MUST be discarded. -Common strategies include Proof of Work (PoW), Verifiable Delay Functions -(VDFs), and Rate-limiting Nullifiers (RLNs). +Common strategies include Proof of Work (PoW), Verifiable Delay Functions (VDFs), and Rate-limiting Nullifiers (RLNs). -The sender is responsible for appending the appropriate spam protection data -(e.g., nonce, timestamp) -to the message payload. The format and verification logic depend on the selected -method. +The sender is responsible for appending the appropriate spam protection data (e.g., nonce, timestamp) to the message payload. +The format and verification logic depend on the selected method. An example using PoW is included in Appendix A. -Note: The spam protection mechanisms described above are intended to protect the -destination application -or protocol from message abuse or flooding. They do not provide protection -against denial-of-service (DoS) or -resource exhaustion attacks targeting the mixnet itself (_e.g.,_ flooding mix -nodes with traffic, -inducing processing overhead, or targeting bandwidth). +Note: +The spam protection mechanisms described above are intended to protect the destination application or protocol from message abuse or flooding. +They do not provide protection against denial-of-service (DoS) or resource exhaustion attacks targeting the mixnet itself (_e.g.,_ flooding mix nodes with traffic, inducing processing overhead, or targeting bandwidth). -Protections against attacks targeting the mixnet itself are not defined in this -specification -but are critical to the long-term robustness of the system. Future versions of -the protocol may -define mechanisms to rate-limit clients, enforce admission control, or -incorporate incentives and -accountability to defend the mixnet itself from abuse. +Protections against attacks targeting the mixnet itself are not defined in this specification but are critical to the long-term robustness of the system. +Future versions of the protocol may define mechanisms to rate-limit clients, enforce admission control, or incorporate incentives and accountability to defend the mixnet itself from abuse. ### 6.4 Cover Traffic -Cover traffic is an optional mechanism used to improve privacy by making the -presence or absence -of actual messages indistinguishable to observers. It helps achieve -_unobservability_ where -a passive adversary cannot determine whether a node is sending real messages or -not. +Cover traffic is an optional mechanism used to improve privacy by making the presence or absence of actual messages indistinguishable to observers. +It helps achieve _unobservability_ where a passive adversary cannot determine whether a node is sending real messages or not. -In the Mix Protocol, cover traffic is limited to _loop messages_—dummy -Sphinx packets -that follow a valid mix path and return to the originating node. These messages -carry no application -payload but are indistinguishable from real messages in structure, size, and -routing behavior. +In the Mix Protocol, cover traffic is limited to _loop messages_—dummy Sphinx packets that follow a valid mix path and return to the originating node. +These messages carry no application payload but are indistinguishable from real messages in structure, size, and routing behavior. -Cover traffic MAY be generated by either mix nodes or senders. The strategy for -generating -such traffic—such as timing and frequency—is pluggable and not -specified -in this document. +Cover traffic MAY be generated by either mix nodes or senders. +The strategy for generating such traffic—such as timing and frequency—is pluggable and not specified in this document. -Implementations that support cover traffic SHOULD generate loop messages at -randomized intervals. -This helps mask actual sending behavior and increases the effective anonymity -set. Timing -strategies such as Poisson processes or exponential delays are commonly used, -but the choice is -left to the implementation. +Implementations that support cover traffic SHOULD generate loop messages at randomized intervals. +This helps mask actual sending behavior and increases the effective anonymity set. +Timing strategies such as Poisson processes or exponential delays are commonly used, but the choice is left to the implementation. -In addition to -enhancing privacy, loop messages can be used to assess network liveness or path -reliability -without requiring explicit acknowledgments. +In addition to enhancing privacy, loop messages can be used to assess network liveness or path reliability without requiring explicit acknowledgments. ### 6.5 Incentivization -The Mix Protocol supports a simple tit-for-tat model to discourage free-riding -and promote -mix node participation. In this model, nodes that wish to send anonymous -messages using the -Mix Protocol MUST also operate a mix node. This requirement ensures that -participants contribute to -the anonymity set they benefit from, fostering a minimal form of fairness and -reciprocity. +The Mix Protocol supports a simple tit-for-tat model to discourage free-riding and promote mix node participation. +In this model, nodes that wish to send anonymous messages using the Mix Protocol MUST also operate a mix node. +This requirement ensures that participants contribute to the anonymity set they benefit from, fostering a minimal form of fairness and reciprocity. -This tit-for-tat model is intentionally lightweight and decentralized. It deters -passive use -of the mixnet by requiring each user to contribute bandwidth and processing -capacity. However, it -does not guarantee the quality of service provided by participating nodes. For -example, it -does not prevent nodes from running low-quality or misbehaving mix instances, -nor does it -deter participation by compromised or transient peers. +This tit-for-tat model is intentionally lightweight and decentralized. +It deters passive use of the mixnet by requiring each user to contribute bandwidth and processing capacity. +However, it does not guarantee the quality of service provided by participating nodes. +For example, it does not prevent nodes from running low-quality or misbehaving mix instances, nor does it deter participation by compromised or transient peers. -The Mix Protocol does not mandate any form of payment, token exchange, or -accounting. More -sophisticated economic models—such as stake-based participation, -credentialed relay networks, -or zero-knowledge proof-of-contribution systems—MAY be layered on top of -the protocol or -enforced via external coordination. +The Mix Protocol does not mandate any form of payment, token exchange, or accounting. +More sophisticated economic models—such as stake-based participation, credentialed relay networks, or zero-knowledge proof-of-contribution systems—MAY be layered on top of the protocol or enforced via external coordination. -Additionally, network operators or application-layer policies MAY require nodes -to maintain -minimum uptime, prove their participation, or adhere to service-level -guarantees. +Additionally, network operators or application-layer policies MAY require nodes to maintain minimum uptime, prove their participation, or adhere to service-level guarantees. -While the Mix Protocol defines a minimum participation requirement, additional -incentivization -extensions are considered pluggable and experimental in this version of the -specification. +While the Mix Protocol defines a minimum participation requirement, additional incentivization extensions are considered pluggable and experimental in this version of the specification. No specific mechanism is standardized. ## 7. Core Mix Protocol Responsibilities -This section defines the core routing behavior of the Mix Protocol, which all -conforming -implementations MUST support. +This section defines the core routing behavior of the Mix Protocol, which all conforming implementations MUST support. -The Mix Protocol defines the logic for anonymously routing messages through the -decentralized -mix network formed by participating libp2p nodes. Each mix node MUST implement -support for: +The Mix Protocol defines the logic for anonymously routing messages through the decentralized mix network formed by participating libp2p nodes. +Each mix node MUST implement support for: - initiating anonymous routing when invoked with a message. - receiving and processing Sphinx packets when selected as a hop in a mix path. -These roles and their required behaviors are defined in the following -subsections. +These roles and their required behaviors are defined in the following subsections. ### 7.1 Protocol Identifier The Mix Protocol is identified by the protocol string `"/mix/1.0.0"`. -All Mix Protocol interactions occur over libp2p streams negotiated using this -identifier. -Each Sphinx packet transmission—whether initiated locally or forwarded as -part of a -mix path—involves opening a new libp2p stream to the next hop. -Implementations MAY optimize -performance by reusing streams where appropriate; see [Section -5.5](#55-stream-management-and-multiplexing) -for more details on stream management. +All Mix Protocol interactions occur over libp2p streams negotiated using this identifier. +Each Sphinx packet transmission—whether initiated locally or forwarded as part of a mix path—involves opening a new libp2p stream to the next hop. +Implementations MAY optimize performance by reusing streams where appropriate; +see [Section 5.5](#55-stream-management-and-multiplexing) for more details on stream management. ### 7.2 Initiation -A mix node initiates anonymous routing only when it is explicitly invoked with a -message -to be routed. As specified in [Section 5.2](#52-mixify-option), the decision to -anonymize a -message is made by the origin protocol. When anonymization is required, the -origin protocol instance -forwards the message to the Mix Entry Layer, which then passes the message to -the local -Mix Protocol instance for routing. +A mix node initiates anonymous routing only when it is explicitly invoked with a message to be routed. +As specified in [Section 5.2](#52-mixify-option), the decision to anonymize a message is made by the origin protocol. +When anonymization is required, the origin protocol instance forwards the message to the Mix Entry Layer, which then passes the message to the local Mix Protocol instance for routing. To perform message initiation, a mix node MUST: - Select a random mix path. - Assign a delay value for each hop and encode it into the Sphinx packet header. -- Wrap message in a Sphinx packet by applying layered encryption in reverse -order of nodes -in the selected mix path. -- Forward the resulting packet to the first mix node in the mix path using the -Mix Protocol. +- Wrap message in a Sphinx packet by applying layered encryption in reverse order of nodes in the selected mix path. +- Forward the resulting packet to the first mix node in the mix path using the Mix Protocol. The Mix Protocol does not interpret message content or origin protocol context. -Each invocation is -stateless, and the implementation MUST NOT retain routing metadata or -per-message state -after the packet is forwarded. +Each invocation is stateless, and the implementation MUST NOT retain routing metadata or per-message state after the packet is forwarded. ### 7.3 Sphinx Packet Receiving and Processing -A mix node that receives a Sphinx packet is oblivious to its position in the -path. The -first hop is indistinguishable from other intermediary hops in terms of -processing and behavior. +A mix node that receives a Sphinx packet is oblivious to its position in the path. +The first hop is indistinguishable from other intermediary hops in terms of processing and behavior. -After decrypting one layer of the Sphinx packet, the node MUST inspect the -routing information. -If this layer indicates that the next hop is the final destination, the packet -MUST be processed -as an exit. Otherwise, it MUST be processed as an intermediary. +After decrypting one layer of the Sphinx packet, the node MUST inspect the routing information. +If this layer indicates that the next hop is the final destination, the packet MUST be processed as an exit. +Otherwise, it MUST be processed as an intermediary. #### 7.3.1 Intermediary Processing @@ -775,8 +431,7 @@ To process a Sphinx packet as an intermediary, a mix node MUST: - Wait for the specified delay. - Forward the updated packet to the next hop using the Mix Protocol. -A mix node performing intermediary processing MUST treat each packet as -stateless and self-contained. +A mix node performing intermediary processing MUST treat each packet as stateless and self-contained. #### 7.3.2 Exit Processing @@ -785,132 +440,79 @@ To process a Sphinx packet as an exit, a mix node MUST: - Extract the plaintext message from the final decrypted packet. - Validate any attached spam protection proof. - Discard the message if spam protection validation fails. -- Forward the valid message to the Mix Exit Layer for delivery to the -destination origin protocol instance. +- Forward the valid message to the Mix Exit Layer for delivery to the destination origin protocol instance. The node MUST NOT retain decrypted content after forwarding. -The routing behavior described in this section relies on the use of -Sphinx packets to preserve unlinkability and confidentiality across -hops. The next section specifies their structure, cryptographic -components, and construction. +The routing behavior described in this section relies on the use of Sphinx packets to preserve unlinkability and confidentiality across hops. +The next section specifies their structure, cryptographic components, and construction. ## 8. Sphinx Packet Format -The Mix Protocol uses the Sphinx packet format to enable unlinkable, multi-hop -message routing -with per-hop confidentiality and integrity. Each message transmitted through the -mix network is -encapsulated in a Sphinx packet constructed by the initiating mix node. The -packet is encrypted in -layers such that each hop in the mix path can decrypt exactly one layer and -obtain the next-hop -routing information and forwarding delay, without learning the complete path or the -message origin. -Only the final hop learns the destination, which is encoded in the innermost -routing layer. +The Mix Protocol uses the Sphinx packet format to enable unlinkable, multi-hop message routing with per-hop confidentiality and integrity. +Each message transmitted through the mix network is encapsulated in a Sphinx packet constructed by the initiating mix node. +The packet is encrypted in layers such that each hop in the mix path can decrypt exactly one layer and obtain the next-hop routing information and forwarding delay, without learning the complete path or the message origin. +Only the final hop learns the destination, which is encoded in the innermost routing layer. -Sphinx packets are self-contained and indistinguishable on the wire, providing -strong metadata -protection. Mix nodes forward packets without retaining state or requiring -knowledge of the -source or destination beyond their immediate routing target. +Sphinx packets are self-contained and indistinguishable on the wire, providing strong metadata protection. +Mix nodes forward packets without retaining state or requiring knowledge of the source or destination beyond their immediate routing target. -To ensure uniformity, each Sphinx packet consists of a fixed-length header and a -payload -that is padded to a fixed maximum size. Although the original message payload -may vary in length, -padding ensures that all packets are identical in size on the wire. This ensures -unlinkability -and protects against correlation attacks based on message size. +To ensure uniformity, each Sphinx packet consists of a fixed-length header and a payload that is padded to a fixed maximum size. +Although the original message payload may vary in length, padding ensures that all packets are identical in size on the wire. +This ensures unlinkability and protects against correlation attacks based on message size. -If a message exceeds the maximum supported payload size, it MUST be fragmented -before being passed -to the Mix Protocol. Fragmentation and reassembly are the responsibility of the -origin protocol -or the top-level application. The Mix Protocol handles only messages that do not -require -fragmentation. +If a message exceeds the maximum supported payload size, it MUST be fragmented before being passed to the Mix Protocol. +Fragmentation and reassembly are the responsibility of the origin protocol or the top-level application. +The Mix Protocol handles only messages that do not require fragmentation. -The structure, encoding, and size constraints of the Sphinx packet are detailed -in the following -subsections. +The structure, encoding, and size constraints of the Sphinx packet are detailed in the following subsections. ### 8.1 Packet Structure Overview -Each Sphinx packet consists of three fixed-length header fields— $α$, -$β$, and $γ$ —followed by a fixed-length encrypted payload $δ$. -Together, these components enable per-hop message processing with strong -confidentiality and integrity guarantees in a stateless and unlinkable manner. +Each Sphinx packet consists of three fixed-length header fields— $α$, $β$, and $γ$ —followed by a fixed-length encrypted payload $δ$. +Together, these components enable per-hop message processing with strong confidentiality and integrity guarantees in a stateless and unlinkable manner. -- **$α$ (Alpha)**: An ephemeral public value. Each mix node uses its private key -and $α$ to -derive a shared session key for that hop. This session key is used to decrypt -and process -one layer of the packet. -- **$β$ (Beta)**: The nested encrypted routing information. It encodes the next -hop address, the forwarding delay, integrity check $γ$ for the next hop, and -the $β$ for subsequent hops. At the final hop, $β$ encodes the destination -address and fixed-length zero padding to preserve uniform size. -- **$γ$ (Gamma)**: A message authentication code computed over $β$ using the -session key derived -from $α$. It ensures header integrity at each hop. -- **$δ$ (Delta)**: The encrypted payload. It consists of the message padded to a -fixed maximum length and -encrypted in layers corresponding to each hop in the mix path. +- **$α$ (Alpha)**: An ephemeral public value. Each mix node uses its private key and $α$ to derive a shared session key for that hop. This session key is used to decrypt and process one layer of the packet. +- **$β$ (Beta)**: The nested encrypted routing information. It encodes the next hop address, the forwarding delay, integrity check $γ$ for the next hop, and the $β$ for subsequent hops. At the final hop, $β$ encodes the destination address and fixed-length zero padding to preserve uniform size. +- **$γ$ (Gamma)**: A message authentication code computed over $β$ using the session key derived from $α$. It ensures header integrity at each hop. +- **$δ$ (Delta)**: The encrypted payload. It consists of the message padded to a fixed maximum length and encrypted in layers corresponding to each hop in the mix path. -At each hop, the mix node derives the session key from $α$, verifies the header -integrity using $γ$, decrypts one layer of $β$ to extract the next hop and -delay, and decrypts one layer of $δ$. It then constructs a new packet with -updated values of $α$, $β$, $γ$, and $δ$, and forwards it to the next hop. At -the final hop, the mix node decrypts the innermost layer of $β$ and $δ$, which -yields the destination address and the original application message -respectively. +At each hop, the mix node derives the session key from $α$, verifies the header integrity using $γ$, decrypts one layer of $β$ to extract the next hop and delay, and decrypts one layer of $δ$. +It then constructs a new packet with updated values of $α$, $β$, $γ$, and $δ$, and forwards it to the next hop. +At the final hop, the mix node decrypts the innermost layer of $β$ and $δ$, which yields the destination address and the original application message respectively. -All Sphinx packets are fixed in size and indistinguishable on the wire. This -uniform format, -combined with layered encryption and per-hop integrity protection, ensures -unlinkability, -tamper resistance, and robustness against correlation attacks. +All Sphinx packets are fixed in size and indistinguishable on the wire. +This uniform format, combined with layered encryption and per-hop integrity protection, ensures unlinkability, tamper resistance, and robustness against correlation attacks. -The structure and semantics of these fields, the cryptographic primitives used, -and the construction -and processing steps are defined in the following subsections. +The structure and semantics of these fields, the cryptographic primitives used, and the construction and processing steps are defined in the following subsections. ### 8.2 Cryptographic Primitives -This section defines the cryptographic primitives used in Sphinx packet -construction and processing. +This section defines the cryptographic primitives used in Sphinx packet construction and processing. -- **Security Parameter**: All cryptographic operations target a minimum of -$κ = 128$ bits of -security, balancing performance with resistance to modern attacks. +- **Security Parameter**: All cryptographic operations target a minimum of $κ = 128$ bits of security, balancing performance with resistance to modern attacks. - **Elliptic Curve Group $\mathbb{G}$**: + - **Curve**: Curve25519 - **Notation**: Let $g$ denote the canonical base point (generator) of $\mathbb{G}$. - - **Purpose**: Used for deriving Diffie–Hellman-style shared key at each hop -using $α$. - - **Representation**: Small 32-byte group elements, efficient for both -encryption and key exchange. - - **Scalar Field**: The curve is defined over the finite field -$\mathbb{Z}_q$, where $q = 2^{252} + 27742317777372353535851937790883648493$. -Ephemeral exponents used in Sphinx packet construction are selected uniformly -at random from $\mathbb{Z}_q^*$, the multiplicative subgroup of $\mathbb{Z}_q$. + - **Purpose**: Used for deriving Diffie–Hellman-style shared key at each hop using $α$. + - **Representation**: Small 32-byte group elements, efficient for both encryption and key exchange. + - **Scalar Field**: The curve is defined over the finite field $\mathbb{Z}_q$, where $q = 2^{252} + 27742317777372353535851937790883648493$. Ephemeral exponents used in Sphinx packet construction are selected uniformly at random from $\mathbb{Z}_q^*$, the multiplicative subgroup of $\mathbb{Z}_q$. - **Hash Function**: + - **Construction**: SHA-256 - **Notation**: The hash function is denoted by $H(\cdot)$ in subsequent sections. - **Key Derivation Function (KDF)**: - - **Purpose**: To derive encryption keys, IVs, and MAC key from the shared -session key at each hop. + + - **Purpose**: To derive encryption keys, IVs, and MAC key from the shared session key at each hop. - **Construction**: SHA-256 hash with output truncated to $128$ bits. - - **Key Derivation**: The KDF key separation labels (_e.g.,_ `"aes_key"`, -`"mac_key"`) -are fixed strings and MUST be agreed upon across implementations. + - **Key Derivation**: The KDF key separation labels (_e.g.,_ `"aes_key"`, `"mac_key"`) are fixed strings and MUST be agreed upon across implementations. - **Symmetric Encryption**: AES-128 in Counter Mode (AES-CTR) + - **Purpose**: To encrypt $β$ and $δ$ for each hop. - **Keys and IVs**: Each derived from the session key for the hop using the KDF. @@ -919,15 +521,13 @@ are fixed strings and MUST be agreed upon across implementations. - **Purpose**: To compute $γ$ for each hop. - **Key**: Derived using KDF from the session key for the hop. -These primitives are used consistently throughout packet construction and -decryption, as described in the following sections. +These primitives are used consistently throughout packet construction and decryption, as described in the following sections. ### 8.3 Packet Component Sizes -This section defines the size of each component in a Sphinx packet, deriving them -from the security parameter and protocol parameters introduced earlier. All Sphinx -packets MUST be fixed in length to ensure uniformity and indistinguishability on -the wire. The serialized packet is structured as follows: +This section defines the size of each component in a Sphinx packet, deriving them from the security parameter and protocol parameters introduced earlier. +All Sphinx packets MUST be fixed in length to ensure uniformity and indistinguishability on the wire. +The serialized packet is structured as follows: ```text +--------+----------+--------+----------+ @@ -938,41 +538,28 @@ the wire. The serialized packet is structured as follows: #### 8.3.1 Header Field Sizes -The header consists of the fields $α$, $β$, and $γ$, totaling a fixed size per -maximum path length: +The header consists of the fields $α$, $β$, and $γ$, totaling a fixed size per maximum path length: -- **$α$ (Alpha)**: 32 bytes - The size of $α$ is determined by the elliptic curve group representation used - (Curve25519), which encodes group elements as 32-byte values. +- **$α$ (Alpha)**: 32 bytes + The size of $α$ is determined by the elliptic curve group representation used (Curve25519), which encodes group elements as 32-byte values. -- **$β$ (Beta)**: $((t + 1)r + 1)κ$ bytes +- **$β$ (Beta)**: $((t + 1)r + 1)κ$ bytes The size of $β$ depends on: - - **Maximum path length ($r$)**: The recommended value of $r=5$ balances - bandwidth versus anonymity tradeoffs. - - **Combined address and delay width ($tκ$)**: The recommended $t=6$ - accommodates standard libp2p relay multiaddress representations plus a - 2-byte delay field. While the actual multiaddress and delay fields may be - shorter, they are padded to $tκ$ bytes to maintain fixed field size. The - structure and rationale for the $tκ$ block and its encoding are specified in - [Section 8.4](#84-address-and-delay-encoding). - Note: This expands on the original - [Sphinx packet format]((https://cypherpunks.ca/~iang/pubs/Sphinx_Oakland09.pdf)), - which embeds a fixed $κ$-byte mix node identifier per hop in $β$. - The Mix Protocol generalizes this to $tκ$ bytes to accommodate libp2p - multiaddresses and forwarding delays while preserving the cryptographic - properties of the original design. + - **Maximum path length ($r$)**: The recommended value of $r=5$ balances bandwidth versus anonymity tradeoffs. + - **Combined address and delay width ($tκ$)**: The recommended $t=6$ accommodates standard libp2p relay multiaddress representations plus a 2-byte delay field. While the actual multiaddress and delay fields may be shorter, they are padded to $tκ$ bytes to maintain fixed field size. The structure and rationale for the $tκ$ block and its encoding are specified in [Section 8.4](#84-address-and-delay-encoding). - - **Per-hop $γ$ size ($κ$)** (defined below): Accounts for the integrity tag - included with each hop’s routing information. + Note: + This expands on the original [Sphinx packet format](<(https://cypherpunks.ca/~iang/pubs/Sphinx_Oakland09.pdf)>), which embeds a fixed $κ$-byte mix node identifier per hop in $β$. + The Mix Protocol generalizes this to $tκ$ bytes to accommodate libp2p multiaddresses and forwarding delays while preserving the cryptographic properties of the original design. - Using the recommended value of $r=5$ and $t=6$, the resulting $β$ size is - $576$ bytes. At the final hop, $β$ encodes the destination address in the - first $tκ-2$ bytes and the remaining bytes are zero-padded. + - **Per-hop $γ$ size ($κ$)** (defined below): Accounts for the integrity tag included with each hop's routing information. -- **$γ$ (Gamma)**: $16$ bytes - The size of $γ$ equals the security parameter $κ$, providing a $κ$-bit integrity - tag at each hop. + Using the recommended value of $r=5$ and $t=6$, the resulting $β$ size is $576$ bytes. + At the final hop, $β$ encodes the destination address in the first $tκ-2$ bytes and the remaining bytes are zero-padded. + +- **$γ$ (Gamma)**: $16$ bytes + The size of $γ$ equals the security parameter $κ$, providing a $κ$-bit integrity tag at each hop. Thus, the total header length is: @@ -998,8 +585,8 @@ $` This subsection defines the size of the encrypted payload $δ$ in a Sphinx packet. -$δ$ contains the application message, padded to a fixed maximum length to ensure -all packets are indistinguishable on the wire. The size of $δ$ is calculated as: +$δ$ contains the application message, padded to a fixed maximum length to ensure all packets are indistinguishable on the wire. +The size of $δ$ is calculated as: $` \begin{aligned} @@ -1009,8 +596,7 @@ $` The recommended total packet size is $4608$ bytes, chosen to: -- Accommodate larger libp2p application messages, such as those commonly -observed in Status chat using Waku (typically ~4KB payloads), +- Accommodate larger libp2p application messages, such as those commonly observed in Status chat using Waku (typically ~4KB payloads), - Allow inclusion of additional data such as SURBs without requiring fragmentation, - Maintain reasonable per-hop processing and bandwidth overhead. @@ -1023,192 +609,116 @@ Payload &= 4608 - 624 \\ \end{aligned} `$ -Implementations MUST account for payload extensions, such as SURBs, -when determining the maximum message size that can be encapsulated in a -single Sphinx packet. Details on SURBs are defined in -[Section X.X]. +Implementations MUST account for payload extensions, such as SURBs, when determining the maximum message size that can be encapsulated in a single Sphinx packet. +Details on SURBs are defined in [Section X.X]. -The following subsection defines the padding and fragmentation requirements for -ensuring this fixed-size constraint. +The following subsection defines the padding and fragmentation requirements for ensuring this fixed-size constraint. #### 8.3.3 Padding and Fragmentation -Implementations MUST ensure that all messages shorter than the maximum payload size -are padded before Sphinx encapsulation to ensure that all packets are -indistinguishable on the wire. Messages larger than the maximum payload size MUST -be fragmented by the origin protocol or top-level application before being passed -to the Mix Protocol. Reassembly is the responsibility of the consuming application, -not the Mix Protocol. +Implementations MUST ensure that all messages shorter than the maximum payload size are padded before Sphinx encapsulation to ensure that all packets are indistinguishable on the wire. +Messages larger than the maximum payload size MUST be fragmented by the origin protocol or top-level application before being passed to the Mix Protocol. +Reassembly is the responsibility of the consuming application, not the Mix Protocol. #### 8.3.4 Anonymity Set Considerations -The fixed maximum packet size is a configurable parameter. Protocols or -applications that choose to configure a different packet size (either larger or -smaller than the default) MUST be aware that using unique or uncommon packet sizes -can reduce their effective anonymity set to only other users of the same size. +The fixed maximum packet size is a configurable parameter. +Protocols or applications that choose to configure a different packet size (either larger or smaller than the default) MUST be aware that using unique or uncommon packet sizes can reduce their effective anonymity set to only other users of the same size. Implementers SHOULD align with widely used defaults to maximize anonymity set size. -Similarly, parameters such as $r$ and $t$ are configurable. Changes to these -parameters affect header size and therefore impact payload size if the total packet -size remains fixed. However, if such changes alter the total packet size on the -wire, the same anonymity set considerations apply. +Similarly, parameters such as $r$ and $t$ are configurable. +Changes to these parameters affect header size and therefore impact payload size if the total packet size remains fixed. +However, if such changes alter the total packet size on the wire, the same anonymity set considerations apply. -The following subsection defines how the next-hop or destination address and -forwarding delay are encoded within $β$ to enable correct routing and mixing -behavior. +The following subsection defines how the next-hop or destination address and forwarding delay are encoded within $β$ to enable correct routing and mixing behavior. ### 8.4 Address and Delay Encoding -Each hop’s $β$ includes a fixed-size block containing the next-hop address and -the forwarding delay, except for the final hop, which encodes the destination -address and a delay-sized zero padding. This section defines the structure and -encoding of that block. +Each hop's $β$ includes a fixed-size block containing the next-hop address and the forwarding delay, except for the final hop, which encodes the destination address and a delay-sized zero padding. +This section defines the structure and encoding of that block. -The combined address and delay block MUST be exactly $tκ$ bytes in length, -as defined in [Section 8.3.1](#831-header-field-sizes), regardless of the -actual address or delay values. The first $(tκ - 2)$ bytes MUST encode the -address, and the final $2$ bytes MUST encode the forwarding delay. -This fixed-length encoding ensures that packets remain indistinguishable on -the wire and prevents correlation attacks based on routing metadata structure. +The combined address and delay block MUST be exactly $tκ$ bytes in length, as defined in [Section 8.3.1](#831-header-field-sizes), regardless of the actual address or delay values. +The first $(tκ - 2)$ bytes MUST encode the address, and the final $2$ bytes MUST encode the forwarding delay. +This fixed-length encoding ensures that packets remain indistinguishable on the wire and prevents correlation attacks based on routing metadata structure. -Implementations MAY use any address and delay encoding format agreed upon -by all participating mix nodes, as long as the combined length is exactly -$tκ$ bytes. The encoding format MUST be interpreted consistently by all -nodes within a deployment. +Implementations MAY use any address and delay encoding format agreed upon by all participating mix nodes, as long as the combined length is exactly $tκ$ bytes. +The encoding format MUST be interpreted consistently by all nodes within a deployment. For interoperability, a recommended default encoding format involves: - Encoding the next-hop or destination address as a libp2p multi-address: - - To keep the address block compact while allowing relay connectivity, each mix - node is limited to one IPv4 circuit relay multiaddress. This ensures that most - nodes can act as mix nodes, including those behind NATs or firewalls. - - In libp2p terms, this combines transport addresses with multiple peer - identities to form an address that describes a relay circuit: - ` - /ip4//tcp//p2p//p2p-circuit/p2p/ - ` - Variants may include directly reachable peers and transports such as - `/quic-v1`, depending on the mix node's supported stack. + + - To keep the address block compact while allowing relay connectivity, each mix node is limited to one IPv4 circuit relay multiaddress. This ensures that most nodes can act as mix nodes, including those behind NATs or firewalls. + - In libp2p terms, this combines transport addresses with multiple peer identities to form an address that describes a relay circuit: + `/ip4//tcp//p2p//p2p-circuit/p2p/` + Variants may include directly reachable peers and transports such as `/quic-v1`, depending on the mix node's supported stack. - IPv6 support is deferred, as it adds $16$ bytes just for the IP field. - - Future revisions may extend this format to support IPv6 or DNS-based - multiaddresses. - + - Future revisions may extend this format to support IPv6 or DNS-based multiaddresses. + With these constraints, the recommended encoding layout is: + - IPv4 address (4 bytes) - Protocol identifier _e.g.,_ TCP or QUIC (1 byte) - Port number (2 bytes) - Peer IDs (39 bytes, post-Base58 decoding) -- Encoding the forwarding delay as an unsigned 16-bit integer (2 bytes), - representing the mean delay in milliseconds for the configured delay - distribution, using big endian network byte order. +- Encoding the forwarding delay as an unsigned 16-bit integer (2 bytes), representing the mean delay in milliseconds for the configured delay distribution, using big endian network byte order. The delay distribution is pluggable, as defined in [Section 6.2](#62-delay-strategy). -If the encoded address or delay is shorter than its respective allocated -field, it MUST be padded with zeros. If it exceeds the allocated size, it -MUST be rejected or truncated according to the implementation policy. +If the encoded address or delay is shorter than its respective allocated field, it MUST be padded with zeros. +If it exceeds the allocated size, it MUST be rejected or truncated according to the implementation policy. -Note: Future versions of the Mix Protocol may support address compression by -encoding only the peer identifier and relying on external peer discovery -mechanisms to retrieve full multiaddresses at runtime. This would allow for -more compact headers and greater address flexibility, but requires fast and -reliable lookup support across deployments. This design is out of scope for -the current version. +Note: +Future versions of the Mix Protocol may support address compression by encoding only the peer identifier and relying on external peer discovery mechanisms to retrieve full multiaddresses at runtime. +This would allow for more compact headers and greater address flexibility, but requires fast and reliable lookup support across deployments. +This design is out of scope for the current version. -With the field sizes and encoding conventions established, the next section describes -how a mix node constructs a complete Sphinx packet when initiating the Mix Protocol. +With the field sizes and encoding conventions established, the next section describes how a mix node constructs a complete Sphinx packet when initiating the Mix Protocol. ### 8.5 Packet Construction -This section defines how a mix node constructs a Sphinx packet when initiating -the Mix Protocol on behalf of a local origin protocol instance. -The construction process wraps the message in a sequence of encryption -layers—one for each hop—such that only the corresponding mix node -can decrypt its layer and retrieve the routing instructions for that hop. +This section defines how a mix node constructs a Sphinx packet when initiating the Mix Protocol on behalf of a local origin protocol instance. +The construction process wraps the message in a sequence of encryption layers—one for each hop—such that only the corresponding mix node can decrypt its layer and retrieve the routing instructions for that hop. #### 8.5.1 Inputs -To initiate the Mix Protocol, the origin protocol instance submits a message -to the Mix Entry Layer on the same node. This layer forwards it to the local -Mix Protocol instance, which constructs a Sphinx packet -using the following REQUIRED inputs: +To initiate the Mix Protocol, the origin protocol instance submits a message to the Mix Entry Layer on the same node. +This layer forwards it to the local Mix Protocol instance, which constructs a Sphinx packet using the following REQUIRED inputs: -- **Application message**: The serialized message provided by the origin - protocol instance. The Mix Protocol instance applies any configured spam - protection mechanism and attaches one or two SURBs prior to encapsulating - the message in the Sphinx packet. The initiating node MUST ensure that - the resulting payload size does not exceed the maximum supported size - defined in [Section 8.3.2](#832-payload-size). -- **Origin protocol codec**: The libp2p protocol string corresponding to the - origin protocol instance. This is included in the payload so that - the exit node can route the message to the intended destination protocol - after decryption. -- **Mix Path length $L$**: The number of mix nodes to include in the path. - The mix path MUST consist of at least three hops, each representing a - distinct mix node. -- **Destination address $Δ$**: The routing address of the intended recipient - of the message. This address is encoded in $(tκ - 2)$ bytes as defined in - [Section 8.4](#84-address-and-delay-encoding) and revealed only at the last hop. +- **Application message**: The serialized message provided by the origin protocol instance. The Mix Protocol instance applies any configured spam protection mechanism and attaches one or two SURBs prior to encapsulating the message in the Sphinx packet. The initiating node MUST ensure that the resulting payload size does not exceed the maximum supported size defined in [Section 8.3.2](#832-payload-size). +- **Origin protocol codec**: The libp2p protocol string corresponding to the origin protocol instance. This is included in the payload so that the exit node can route the message to the intended destination protocol after decryption. +- **Mix Path length $L$**: The number of mix nodes to include in the path. The mix path MUST consist of at least three hops, each representing a distinct mix node. +- **Destination address $Δ$**: The routing address of the intended recipient of the message. This address is encoded in $(tκ - 2)$ bytes as defined in [Section 8.4](#84-address-and-delay-encoding) and revealed only at the last hop. #### 8.5.2 Construction Steps -This subsection defines how the initiating mix node constructs a complete -Sphinx packet using the inputs defined in -[Section 8.5.1](#851-inputs). The construction MUST -follow the cryptographic structure defined in -[Section 8.1](#81-packet-structure-overview), use the primitives specified in -[Section 8.2](#82-cryptographic-primitives), and adhere to the component sizes -and encoding formats from [Section 8.3](#83-packet-component-sizes) and -[Section 8.4](#84-address-and-delay-encoding). +This subsection defines how the initiating mix node constructs a complete Sphinx packet using the inputs defined in [Section 8.5.1](#851-inputs). +The construction MUST follow the cryptographic structure defined in [Section 8.1](#81-packet-structure-overview), use the primitives specified in [Section 8.2](#82-cryptographic-primitives), and adhere to the component sizes and encoding formats from [Section 8.3](#83-packet-component-sizes) and [Section 8.4](#84-address-and-delay-encoding). The construction MUST proceed as follows: 1. **Prepare Application Message** - - Apply any configured spam protection mechanism (_e.g.,_ PoW, VDF, RLN) - to the serialized message. Spam protection mechanisms are pluggable as defined - in [Section 6.3](#63-spam-protection). - - Attach one or more SURBs, if required. Their format and processing are - specified in [Section X.X]. - - Append the origin protocol codec in a format that enables the exit node to - reliably extract it during parsing. A recommended encoding approach is to - prefix the codec string with its length, encoded as a compact varint field - limited to two bytes. Regardless of the scheme used, implementations MUST - agree on the format within a deployment to ensure deterministic decoding. - - Pad the result to the maximum application message length of $3968$ bytes - using a deterministic padding scheme. This value is derived from the fixed - payload size in [Section 8.3.2](#832-payload-size) ($3984$ bytes) minus the - security parameter $κ = 16$ bytes defined in - [Section 8.2](#82-cryptographic-primitives). The chosen scheme MUST yield a - fixed-size padded output and MUST be consistent across all mix nodes to - ensure correct interpretation during unpadding. For example, schemes that - explicitly encode the padding length and prepend zero-valued padding bytes - MAY be used. - - Let the resulting message be $m$. + - Apply any configured spam protection mechanism (_e.g.,_ PoW, VDF, RLN) to the serialized message. Spam protection mechanisms are pluggable as defined in [Section 6.3](#63-spam-protection). + - Attach one or more SURBs, if required. Their format and processing are specified in [Section X.X]. + - Append the origin protocol codec in a format that enables the exit node to reliably extract it during parsing. A recommended encoding approach is to prefix the codec string with its length, encoded as a compact varint field limited to two bytes. Regardless of the scheme used, implementations MUST agree on the format within a deployment to ensure deterministic decoding. + - Pad the result to the maximum application message length of $3968$ bytes using a deterministic padding scheme. This value is derived from the fixed payload size in [Section 8.3.2](#832-payload-size) ($3984$ bytes) minus the security parameter $κ = 16$ bytes defined in [Section 8.2](#82-cryptographic-primitives). The chosen scheme MUST yield a fixed-size padded output and MUST be consistent across all mix nodes to ensure correct interpretation during unpadding. For example, schemes that explicitly encode the padding length and prepend zero-valued padding bytes MAY be used. + - Let the resulting message be $m$. 2. **Select A Mix Path** - - First obtain an unbiased random sample of live, routable mix nodes using - some discovery mechanism. The choice of discovery mechanism is - deployment-specific as defined in [Section 6.1](#61-discovery). The - discovery mechanism MUST be unbiased and provide, at a minimum, the - multiaddress and X25519 public key of each mix node. - - From this sample, choose a random mix path of length $L \geq 3$. As defined - in [Section 2](#2-terminology), a mix path is a non-repeating sequence of - mix nodes. + - First obtain an unbiased random sample of live, routable mix nodes using some discovery mechanism. The choice of discovery mechanism is deployment-specific as defined in [Section 6.1](#61-discovery). The discovery mechanism MUST be unbiased and provide, at a minimum, the multiaddress and X25519 public key of each mix node. + - From this sample, choose a random mix path of length $L \geq 3$. As defined in [Section 2](#2-terminology), a mix path is a non-repeating sequence of mix nodes. - For each hop $i \in \{0 \ldots L-1\}$: - - Retrieve the multiaddress and corresponding X25519 public key $y_i$ of - the $i$-th mix node. - - Encode the multiaddress in $(tκ - 2)$ bytes as defined in - [Section 8.4](#84-address-and-delay-encoding). Let the resulting encoded - multiaddress be $\mathrm{addr\_i}$. + - Retrieve the multiaddress and corresponding X25519 public key $y_i$ of the $i$-th mix node. + - Encode the multiaddress in $(tκ - 2)$ bytes as defined in [Section 8.4](#84-address-and-delay-encoding). Let the resulting encoded multiaddress be $\mathrm{addr\_i}$. 3. **Wrap Plaintext Payload In Sphinx Packet** a. **Compute Ephemeral Secrets** - Choose a random private exponent $x \in_R \mathbb{Z}_q^*$. - - Initialize: + - Initialize: $` \begin{aligned} α_0 &= g^x \\ @@ -1216,7 +726,7 @@ The construction MUST proceed as follows: b_0 &= H(α_0\ |\ s_0) \end{aligned} `$ - - For each hop $i$ (from $1$ to $L-1$), compute: + - For each hop $i$ (from $1$ to $L-1$), compute: $` \begin{aligned} α_i &= α_{i-1}^{b_{i-1}} \\ @@ -1225,13 +735,11 @@ The construction MUST proceed as follows: \end{aligned} `$ - Note that the length of $α_i$ is $32$ bytes, $0 \leq i \leq L-1$ as defined in - [Section 8.3.1](#831-header-field-sizes). + Note that the length of $α_i$ is $32$ bytes, $0 \leq i \leq L-1$ as defined in [Section 8.3.1](#831-header-field-sizes). - b. **Compute Per-Hop Filler Strings** - Filler strings are encrypted strings that are appended to the header during - encryption. They ensure that the header length remains constant across hops, - regardless of the position of a node in the mix path. + b. **Compute Per-Hop Filler Strings** + Filler strings are encrypted strings that are appended to the header during encryption. + They ensure that the header length remains constant across hops, regardless of the position of a node in the mix path. To compute the sequence of filler strings, perform the following steps: @@ -1249,9 +757,7 @@ The construction MUST proceed as follows: \end{array} `$ - - Compute the filler string $Φ_i$ using $\text{AES-CTR}^\prime_i$, - which is AES-CTR encryption with the keystream starting from - index $((t+1)(r-i)+t+2)κ$ : + - Compute the filler string $Φ_i$ using $\text{AES-CTR}^\prime_i$, which is AES-CTR encryption with the keystream starting from index $((t+1)(r-i)+t+2)κ$ : $` \begin{array}{l} @@ -1264,18 +770,13 @@ The construction MUST proceed as follows: Note that the length of $Φ_i$ is $(t+1)iκ$, $0 \leq i \leq L-1$. c. **Construct Routing Header** - The routing header as defined in - [Section 8.1](#81-packet-structure-overview) is the encrypted structure - that carries the forwarding instructions for each hop. It ensures that a - mix node can learn only its immediate next hop and forwarding delay without - inferring the full path. + The routing header as defined in [Section 8.1](#81-packet-structure-overview) is the encrypted structure that carries the forwarding instructions for each hop. + It ensures that a mix node can learn only its immediate next hop and forwarding delay without inferring the full path. - Filler strings computed in the previous step are appended during encryption - to ensure that the header length remains constant across hops. This prevents - a node from distinguishing its position in the path based on header size. + Filler strings computed in the previous step are appended during encryption to ensure that the header length remains constant across hops. + This prevents a node from distinguishing its position in the path based on header size. - To construct the routing header, perform the following steps for each hop - $i = L-1$ down to $0$, recursively: + To construct the routing header, perform the following steps for each hop $i = L-1$ down to $0$, recursively: - Derive per-hop AES key, MAC key, and IV: @@ -1289,17 +790,13 @@ The construction MUST proceed as follows: \mathrm{KDF}(\text{"iv"} \mid s_i) \end{array} `$ - - - Set the per hop two-byte encoded delay $\mathrm{delay}_i$ as defined in - [Section 8.4](#84-address-and-delay-encoding): + + - Set the per hop two-byte encoded delay $\mathrm{delay}_i$ as defined in [Section 8.4](#84-address-and-delay-encoding): + - If final hop (_i.e.,_ $i = L - 1$), encode two byte zero padding. - - For all other hop $i,\ i < L - 1$, select the mean forwarding delay - for the delay strategy configured by the application, and encode it as a - two-byte value. The delay strategy is pluggable, as defined in - [Section 6.2](#62-delay-strategy). - - - Using the derived keys and encoded forwarding delay, compute the nested - encrypted routing information $β_i$: + - For all other hop $i,\ i < L - 1$, select the mean forwarding delay for the delay strategy configured by the application, and encode it as a two-byte value. The delay strategy is pluggable, as defined in [Section 6.2](#62-delay-strategy). + + - Using the derived keys and encoded forwarding delay, compute the nested encrypted routing information $β_i$: - If $i = L-1$ (_i.e.,_ exit node): @@ -1323,8 +820,7 @@ The construction MUST proceed as follows: \end{array} `$ - Note that the length of $\beta_i$ is $(r(t+1)+1)κ$, $0 \leq i \leq L-1$ - as defined in [Section 8.3.1](#831-header-field-sizes). + Note that the length of $\beta_i$ is $(r(t+1)+1)κ$, $0 \leq i \leq L-1$ as defined in [Section 8.3.1](#831-header-field-sizes). - Compute the message authentication code $γ_i$: @@ -1335,17 +831,13 @@ The construction MUST proceed as follows: \end{array} `$ - Note that the length of $\gamma_i$ is $κ$, $0 \leq i \leq L-1$ as defined in - [Section 8.3.1](#831-header-field-sizes). + Note that the length of $\gamma_i$ is $κ$, $0 \leq i \leq L-1$ as defined in [Section 8.3.1](#831-header-field-sizes). d. **Encrypt Payload** - The encrypted payload $δ$ contains the message $m$ defined in Step 1, - prepended with a $κ$-byte string of zeros. It is encrypted in layers such that - each hop in the mix path removes exactly one layer using the per-hop session - key. This ensures that only the final hop (_i.e.,_ the exit node) can fully - recover $m$, validate its integrity, and forward it to the destination. - To compute the encrypted payload, perform the following steps for each hop - $i = L-1$ down to $0$, recursively: + The encrypted payload $δ$ contains the message $m$ defined in Step 1, prepended with a $κ$-byte string of zeros. + It is encrypted in layers such that each hop in the mix path removes exactly one layer using the per-hop session key. + This ensures that only the final hop (_i.e.,_ the exit node) can fully recover $m$, validate its integrity, and forward it to the destination. + To compute the encrypted payload, perform the following steps for each hop $i = L-1$ down to $0$, recursively: - Derive per-hop AES key and IV: @@ -1357,7 +849,7 @@ The construction MUST proceed as follows: \mathrm{KDF}(\text{"δ\_iv"} \mid s_i) \end{array} `$ - + - Using the derived keys, compute the encrypted payload $δ_i$: - If $i = L-1$ (_i.e.,_ exit node): @@ -1381,13 +873,10 @@ The construction MUST proceed as follows: Note that the length of $\delta_i$, $0 \leq i \leq L-1$ is $|m| + κ$ bytes. - Given that the derived size of $\delta_i$ is $3984$ bytes as defined in - [Section 8.3.2](#832-payload-size), this allows $m$ to be of length - $3984-16 = 3968$ bytes as defined in Step 1. + Given that the derived size of $\delta_i$ is $3984$ bytes as defined in [Section 8.3.2](#832-payload-size), this allows $m$ to be of length $3984-16 = 3968$ bytes as defined in Step 1. e. **Assemble Final Packet** - The final Sphinx packet is structured as defined in - [Section 8.3](#83-packet-component-sizes): + The final Sphinx packet is structured as defined in [Section 8.3](#83-packet-component-sizes): ```text α = α_0 // 32 bytes @@ -1396,70 +885,51 @@ The construction MUST proceed as follows: δ = δ_0 // 3984 bytes ``` - Serialize the final packet using a consistent format and - prepare it for transmission. + Serialize the final packet using a consistent format and prepare it for transmission. f. **Transmit Packet** - - Sample a randomized delay from the same distribution family used for - per-hop delays (in Step 3.e.) with an independently chosen mean. - This delay prevents timing correlation when multiple Sphinx packets are - sent in quick succession. Such bursts may occur when an upstream protocol - fragments a large message, or when several messages are sent close together. + - Sample a randomized delay from the same distribution family used for per-hop delays (in Step 3.e.) with an independently chosen mean. - - After the randomized delay elapses, transmit the serialized packet to - the first hop via a libp2p stream negotiated under the - `"/mix/1.0.0"` protocol identifier. + This delay prevents timing correlation when multiple Sphinx packets are sent in quick succession. + Such bursts may occur when an upstream protocol fragments a large message, or when several messages are sent close together. - Implementations MAY reuse an existing stream to the first hop as - described in [Section 5.5](#55-stream-management-and-multiplexing), if - doing so does not introduce any observable linkability between the - packets. + - After the randomized delay elapses, transmit the serialized packet to the first hop via a libp2p stream negotiated under the `"/mix/1.0.0"` protocol identifier. -Once a Sphinx packet is constructed and transmitted by the initiating node, it is -processed hop-by-hop by the remaining mix nodes in the path. Each node receives -the packet over a libp2p stream negotiated under the `"/mix/1.0.0"` protocol. -The following subsection defines the per-hop packet handling logic expected of -each mix node, depending on whether it acts as an intermediary or an exit. + Implementations MAY reuse an existing stream to the first hop as described in [Section 5.5](#55-stream-management-and-multiplexing), if doing so does not introduce any observable linkability between the packets. + +Once a Sphinx packet is constructed and transmitted by the initiating node, it is processed hop-by-hop by the remaining mix nodes in the path. +Each node receives the packet over a libp2p stream negotiated under the `"/mix/1.0.0"` protocol. +The following subsection defines the per-hop packet handling logic expected of each mix node, depending on whether it acts as an intermediary or an exit. ### 8.6 Sphinx Packet Handling -Each mix node MUST implement a handler for incoming data received over -libp2p streams negotiated under the `"/mix/1.0.0"` protocol identifier. -The incoming stream may have been reused by the previous hop, as described -in [Section 5.5](#55-stream-management-and-multiplexing). Implementations -MUST ensure that packet handling remains stateless and unlinkable, -regardless of stream reuse. +Each mix node MUST implement a handler for incoming data received over libp2p streams negotiated under the `"/mix/1.0.0"` protocol identifier. +The incoming stream may have been reused by the previous hop, as described in [Section 5.5](#55-stream-management-and-multiplexing). +Implementations MUST ensure that packet handling remains stateless and unlinkable, regardless of stream reuse. -Upon receiving the stream payload, the node MUST interpret it as a Sphinx packet -and process it in one of two roles—intermediary or exit— as defined in -[Section 7.3](#73-sphinx-packet-receiving-and-processing). This section defines -the exact behavior for both roles. +Upon receiving the stream payload, the node MUST interpret it as a Sphinx packet and process it in one of two roles—intermediary or exit— as defined in [Section 7.3](#73-sphinx-packet-receiving-and-processing). +This section defines the exact behavior for both roles. #### 8.6.1 Shared Preprocessing -Upon receiving a stream payload over a libp2p stream, the mix node MUST first -deserialize it into a Sphinx packet `(α, β, γ, δ)`. +Upon receiving a stream payload over a libp2p stream, the mix node MUST first deserialize it into a Sphinx packet `(α, β, γ, δ)`. -The deserialized fields MUST match the sizes defined in [Section 8.5.2](#852-construction-steps) -step 3.e., and the total packet length MUST match the fixed packet size defined in -[Section 8.3.2](#832-payload-size). +The deserialized fields MUST match the sizes defined in [Section 8.5.2](#852-construction-steps) step 3.e., and the total packet length MUST match the fixed packet size defined in [Section 8.3.2](#832-payload-size). -If the stream payload does not match the expected length, it MUST be discarded and -the processing MUST terminate. +If the stream payload does not match the expected length, it MUST be discarded and the processing MUST terminate. After successful deserialization, the mix node performs the following steps: 1. **Derive Session Key** - Let $x \in \mathbb{Z}_q^*$ denote the node's X25519 private key. + Let $x \in \mathbb{Z}_q^*$ denote the node's X25519 private key. Compute the shared secret $s = α^x$. 2. **Check for Replays** - Compute the tag $H(s)$. - - If the tag exists in the node's table of previously seen tags, - discard the packet and terminate processing. + - If the tag exists in the node's table of previously seen tags, discard the packet and terminate processing. - Otherwise, store the tag in the table. The table MAY be flushed when the node rotates its private key. @@ -1510,13 +980,9 @@ After successful deserialization, the mix node performs the following steps: \end{array} `$ - This step removes the filler string appended during header encryption in - [Section 8.5.2](#852-construction-steps) step 3.c. and - yields the plaintext routing information for this hop. + This step removes the filler string appended during header encryption in [Section 8.5.2](#852-construction-steps) step 3.c. and yields the plaintext routing information for this hop. - The routing block $B$ MUST be parsed according to the rules and field layout - defined in [Section 8.6.2](#862-node-role-determination) to determine - whether the current node is an intermediary or the exit. + The routing block $B$ MUST be parsed according to the rules and field layout defined in [Section 8.6.2](#862-node-role-determination) to determine whether the current node is an intermediary or the exit. 5. **Decrypt One Layer of the Payload** @@ -1540,39 +1006,26 @@ After successful deserialization, the mix node performs the following steps: \end{array} `$ - The resulting $δ'$ is the decrypted payload for this hop and MUST be - interpreted depending on the parsed node's role, determined by $B$, as - described in [Section 8.6.2](#862-node-role-determination). + The resulting $δ'$ is the decrypted payload for this hop and MUST be interpreted depending on the parsed node's role, determined by $B$, as described in [Section 8.6.2](#862-node-role-determination). #### 8.6.2 Node Role Determination -As described in [Section 8.6.1](#861-shared-preprocessing), the mix node -obtains the routing block $B$ by decrypting one layer of the encrypted -header $β$. +As described in [Section 8.6.1](#861-shared-preprocessing), the mix node obtains the routing block $B$ by decrypting one layer of the encrypted header $β$. -At this stage, the node MUST determine whether it is an intermediary -or the exit based on the prefix of $B$, in accordance with the construction of -$β_i$ defined in [Section 8.5.2](#852-construction-steps) step 3.c.: +At this stage, the node MUST determine whether it is an intermediary or the exit based on the prefix of $B$, in accordance with the construction of $β_i$ defined in [Section 8.5.2](#852-construction-steps) step 3.c.: -- If the first $(tκ - 2)$ bytes of $B$ contain a nonzero-encoded - address, immediately followed by a two-byte zero delay, - and then $((t + 1)(r - L) + t + 2)κ$ bytes of all-zero padding, - process the packet as an exit. +- If the first $(tκ - 2)$ bytes of $B$ contain a nonzero-encoded address, immediately followed by a two-byte zero delay, and then $((t + 1)(r - L) + t + 2)κ$ bytes of all-zero padding, process the packet as an exit. - Otherwise, process the packet as an intermediary. The following subsections define the precise behavior for each case. #### 8.6.3 Intermediary Processing -Once the node determines its role as an intermediary following the steps in -[Section 8.6.2](#862-node-role-determination), it MUST perform the following -steps to interpret routing block $B$ and decrypted payload $δ'$ obtained in -[Section 8.6.1](#861-shared-preprocessing): +Once the node determines its role as an intermediary following the steps in [Section 8.6.2](#862-node-role-determination), it MUST perform the following steps to interpret routing block $B$ and decrypted payload $δ'$ obtained in [Section 8.6.1](#861-shared-preprocessing): 1. **Parse Routing Block** - Parse the routing block $B$ according to the $β_i$, $i \neq L - 1$ construction - defined in [Section 8.5.2](#852-construction-steps) step 3.c.: + Parse the routing block $B$ according to the $β_i$, $i \neq L - 1$ construction defined in [Section 8.5.2](#852-construction-steps) step 3.c.: - Extract the first $(tκ - 2)$ bytes of $B$ as the next hop address $\mathrm{addr}$ @@ -1610,12 +1063,9 @@ steps to interpret routing block $B$ and decrypted payload $δ'$ obtained in 2. **Update Header Fields** - Update the header fields according to the construction steps - defined in [Section 8.5.2](#852-construction-steps): + Update the header fields according to the construction steps defined in [Section 8.5.2](#852-construction-steps): - - Compute the next hop ephemeral public value $α'$, deriving the blinding factor - $b$ from the shared secret $s$ computed in - [Section 8.6.1](#861-shared-preprocessing) step 1. + - Compute the next hop ephemeral public value $α'$, deriving the blinding factor $b$ from the shared secret $s$ computed in [Section 8.6.1](#861-shared-preprocessing) step 1. $` \begin{aligned} @@ -1624,18 +1074,14 @@ steps to interpret routing block $B$ and decrypted payload $δ'$ obtained in \end{aligned} `$ - - Use the $β'$ and $γ'$ extracted in Step 1. as the routing information and - MAC respectively in the outgoing packet. + - Use the $β'$ and $γ'$ extracted in Step 1. as the routing information and MAC respectively in the outgoing packet. 3. **Update Payload** - Use the decrypted payload $δ'$ computed in - [Section 8.6.1](#861-shared-preprocessing) step 5. as the payload in the - outgoing packet. + Use the decrypted payload $δ'$ computed in [Section 8.6.1](#861-shared-preprocessing) step 5. as the payload in the outgoing packet. 4. **Assemble Final Packet** - The final Sphinx packet is structured as defined in - [Section 8.3](#83-packet-component-sizes): + The final Sphinx packet is structured as defined in [Section 8.3](#83-packet-component-sizes): ```text α = α' // 32 bytes @@ -1644,49 +1090,32 @@ steps to interpret routing block $B$ and decrypted payload $δ'$ obtained in δ = δ' // 3984 bytes ``` - Serialize $α'$ using the same format used in - [Section 8.5.2](#852-construction-steps). The remaining fields are - already fixed-length buffers and do not require further - transformation. + Serialize $α'$ using the same format used in [Section 8.5.2](#852-construction-steps). + The remaining fields are already fixed-length buffers and do not require further transformation. 5. **Transmit Packet** - - Interpret the $\mathrm{addr}$ and $\mathrm{delay}$ extracted in - Step 1. according to the encoding format used during construction in - [Section 8.5.2](#852-construction-steps) Step 3.c. + - Interpret the $\mathrm{addr}$ and $\mathrm{delay}$ extracted in Step 1. according to the encoding format used during construction in [Section 8.5.2](#852-construction-steps) Step 3.c. - - Sample the actual forwarding delay from the configured delay distribution, - using the decoded mean delay value as the distribution parameter. + - Sample the actual forwarding delay from the configured delay distribution, using the decoded mean delay value as the distribution parameter. - - After the forwarding delay elapses, transmit the serialized packet to - the next hop address via a libp2p stream negotiated under the `"/mix/1.0.0"` - protocol identifier. + - After the forwarding delay elapses, transmit the serialized packet to the next hop address via a libp2p stream negotiated under the `"/mix/1.0.0"` protocol identifier. - Implementations MAY reuse an existing stream to the next hop as - described in [Section 5.5](#55-stream-management-and-multiplexing), if - doing so does not introduce any observable linkability between the - packets. + Implementations MAY reuse an existing stream to the next hop as described in [Section 5.5](#55-stream-management-and-multiplexing), if doing so does not introduce any observable linkability between the packets. 6. **Erase State** - - After transmission, erase all temporary values securely from memory, - including session keys, decrypted content, and routing metadata. + - After transmission, erase all temporary values securely from memory, including session keys, decrypted content, and routing metadata. - - If any error occurs—such as malformed header, invalid delay, or - failed stream transmission—silently discard the packet and do not - send any error response. + - If any error occurs—such as malformed header, invalid delay, or failed stream transmission—silently discard the packet and do not send any error response. #### 8.6.4 Exit Processing -Once the node determines its role as an exit following the steps in -[Section 8.6.2](#862-node-role-determination), it MUST perform the following -steps to interpret routing block $B$ and decrypted payload $δ'$ obtained in -[Section 8.6.1](#861-shared-preprocessing): +Once the node determines its role as an exit following the steps in [Section 8.6.2](#862-node-role-determination), it MUST perform the following steps to interpret routing block $B$ and decrypted payload $δ'$ obtained in [Section 8.6.1](#861-shared-preprocessing): 1. **Parse Routing Block** - Parse the routing block $B$ according to the $β_i$, $i = L - 1$ - construction defined in [Section 8.5.2](#852-construction-steps) step 3.c.: + Parse the routing block $B$ according to the $β_i$, $i = L - 1$ construction defined in [Section 8.5.2](#852-construction-steps) step 3.c.: - Extract first $(tκ - 2)$ bytes of $B$ as the destination address $Δ$ @@ -1698,8 +1127,7 @@ steps to interpret routing block $B$ and decrypted payload $δ'$ obtained in 2. **Recover Padded Application Message** - - Verify the decrypted payload $δ'$ computed in - [Section 8.6.1](#861-shared-preprocessing) step 5.: + - Verify the decrypted payload $δ'$ computed in [Section 8.6.1](#861-shared-preprocessing) step 5.: $` \begin{array}{l} @@ -1721,12 +1149,10 @@ steps to interpret routing block $B$ and decrypted payload $δ'$ obtained in 3. **Extract Application Message** - Interpret recovered $m$ according to the construction steps - defined in [Section 8.5.2](#852-construction-steps) step 1.: + Interpret recovered $m$ according to the construction steps defined in [Section 8.5.2](#852-construction-steps) step 1.: + + - First, unpad $m$ using the deterministic padding scheme defined during construction. - - First, unpad $m$ using the deterministic padding scheme defined during - construction. - - Next, parse the unpadded message deterministically to extract: - optional spam protection proof @@ -1734,274 +1160,184 @@ steps to interpret routing block $B$ and decrypted payload $δ'$ obtained in - the origin protocol codec - the serialized application message - - Parse and deserialize the metadata fields required for spam validation, - SURB extraction, and protocol codec identification, consistent with the - format and extensions applied by the initiator. - The application message itself MUST remain serialized. + - Parse and deserialize the metadata fields required for spam validation, SURB extraction, and protocol codec identification, consistent with the format and extensions applied by the initiator. + The application message itself MUST remain serialized. - If parsing fails at any stage, discard $m$ and terminate processing. 4. **Handoff to Exit Layer** - - Hand off the serialized application message, the origin protocol codec, and - destination address $Δ$ (extracted in step 1.) to the local Exit layer for - further processing and delivery. + - Hand off the serialized application message, the origin protocol codec, and destination address $Δ$ (extracted in step 1.) to the local Exit layer for further processing and delivery. - - The Exit Layer is responsible for establishing a client-only connection and - forwarding the message to the destination. Implementations MAY reuse an - existing stream to the destination, if doing so does not introduce any - observable linkability between forwarded messages. + - The Exit Layer is responsible for establishing a client-only connection and forwarding the message to the destination. Implementations MAY reuse an existing stream to the destination, if doing so does not introduce any observable linkability between forwarded messages. ## 9. Security Considerations -This section describes the security guarantees and limitations of the Mix -Protocol. It begins by outlining the anonymity properties provided by the core -protocol when routing messages through the mix network. It then discusses the -trust assumptions required at the edges of the network, particularly at the -final hop. Finally, it presents an alternative trust model for destinations -that support Mix Protocol directly, followed by a summary of broader -limitations and areas that may be addressed in future iterations. +This section describes the security guarantees and limitations of the Mix Protocol. +It begins by outlining the anonymity properties provided by the core protocol when routing messages through the mix network. +It then discusses the trust assumptions required at the edges of the network, particularly at the final hop. +Finally, it presents an alternative trust model for destinations that support Mix Protocol directly, followed by a summary of broader limitations and areas that may be addressed in future iterations. ### 9.1 Security Guarantees of the Core Mix Protocol -The core Mix Protocol—comprising anonymous routing through a sequence of -mix nodes using Sphinx packets—provides the following security guarantees: +The core Mix Protocol—comprising anonymous routing through a sequence of mix nodes using Sphinx packets—provides the following security guarantees: -- **Sender anonymity**: Each message is wrapped in layered encryption and - routed independently, making it unlinkable to the sender even if multiple - mix nodes are colluding. -- **Metadata protection**: All messages are fixed in size and indistinguishable - on the wire. Sphinx packets reveal only the immediate next hop and delay to - each mix node. No intermediate node learns its position in the path or the - total pathlength. -- **Traffic analysis resistance**: Continuous-time mixing with randomized - per-hop delays reduces the risk of timing correlation and input-output - linkage. -- **Per-hop confidentiality and integrity**: Each hop decrypts only its - assigned layer of the Sphinx packet and verifies header integrity via a - per-hop MAC. -- **No long-term state**: All routing is stateless. Mix nodes do not maintain - per-message metadata, reducing the surface for correlation attacks. +- **Sender anonymity**: Each message is wrapped in layered encryption and routed independently, making it unlinkable to the sender even if multiple mix nodes are colluding. +- **Metadata protection**: All messages are fixed in size and indistinguishable on the wire. Sphinx packets reveal only the immediate next hop and delay to each mix node. No intermediate node learns its position in the path or the total pathlength. +- **Traffic analysis resistance**: Continuous-time mixing with randomized per-hop delays reduces the risk of timing correlation and input-output linkage. +- **Per-hop confidentiality and integrity**: Each hop decrypts only its assigned layer of the Sphinx packet and verifies header integrity via a per-hop MAC. +- **No long-term state**: All routing is stateless. Mix nodes do not maintain per-message metadata, reducing the surface for correlation attacks. These guarantees hold only within the boundaries of the Mix Protocol. -Additional trust assumptions are introduced at the edges, particularly at the -final hop, where the decrypted message is handed off to the Mix Exit Layer for -delivery to the destination outside the mixnet. The next subsection discusses -these trust assumptions in detail. +Additional trust assumptions are introduced at the edges, particularly at the final hop, where the decrypted message is handed off to the Mix Exit Layer for delivery to the destination outside the mixnet. +The next subsection discusses these trust assumptions in detail. ### 9.2 Exit Node Trust Model -The Mix Protocol ensures strong sender anonymity and metadata protection -between the Mix Entry and Exit layers. However, once a Sphinx packet is -decrypted at the final hop, additional trust assumptions are introduced. -The node processing the final layer of encryption is trusted to forward the -correct message to the destination and return any reply using the provided -reply key. This section outlines the resulting trust boundaries. +The Mix Protocol ensures strong sender anonymity and metadata protection between the Mix Entry and Exit layers. +However, once a Sphinx packet is decrypted at the final hop, additional trust assumptions are introduced. +The node processing the final layer of encryption is trusted to forward the correct message to the destination and return any reply using the provided reply key. +This section outlines the resulting trust boundaries. #### 9.2.1 Message Delivery and Origin Trust -At the final hop, the decrypted Sphinx packet reveals the plaintext message -and destination address. The exit node is then trusted to deliver this message -to the destination application, and—if a reply is expected— -to return the response using the embedded reply key. +At the final hop, the decrypted Sphinx packet reveals the plaintext message and destination address. +The exit node is then trusted to deliver this message to the destination application, and—if a reply is expected—to return the response using the embedded reply key. -In this model, the exit node becomes a privileged middleman. It has full -visibility into the decrypted payload. Specifically, the exit node could tamper -with either direction of communication without detection: +In this model, the exit node becomes a privileged middleman. +It has full visibility into the decrypted payload. +Specifically, the exit node could tamper with either direction of communication without detection: - It may alter or drop the forwarded message. -- It may fabricate a reply instead of forwarding the actual response from the - destination. +- It may fabricate a reply instead of forwarding the actual response from the destination. -This limitation is consistent with the broader mixnet trust model. While -intermediate nodes are constrained by layered encryption, edge nodes -—specifically the initiating and the exit nodes in the path— -are inherently more privileged and operate outside the cryptographic protections -of the mixnet. +This limitation is consistent with the broader mixnet trust model. +While intermediate nodes are constrained by layered encryption, edge nodes—specifically the initiating and the exit nodes in the path—are inherently more privileged and operate outside the cryptographic protections of the mixnet. -In systems like Tor, such exit-level tampering is mitigated by long-lived circuits -that allow endpoints to negotiate shared session keys (_e.g.,_ via TLS). A -malicious exit cannot forge a valid forward message or response without access to -these session secrets. +In systems like Tor, such exit-level tampering is mitigated by long-lived circuits that allow endpoints to negotiate shared session keys (_e.g.,_ via TLS). +A malicious exit cannot forge a valid forward message or response without access to these session secrets. -The Mix Protocol, by contrast, is stateless and message-based. Each message is -routed independently, with no persistent circuit or session context. As a -result, endpoints cannot correlate messages, establish session keys, or validate -message origin. That is, the exit remains a necessary point of trust for message -delivery and response handling. +The Mix Protocol, by contrast, is stateless and message-based. +Each message is routed independently, with no persistent circuit or session context. +As a result, endpoints cannot correlate messages, establish session keys, or validate message origin. +That is, the exit remains a necessary point of trust for message delivery and response handling. -The next subsection describes a related limitation: the exit’s ability to pose -as a legitimate client to the destination’s origin protocol, and how that -can be abused to bypass application-layer expectations. +The next subsection describes a related limitation: +the exit's ability to pose as a legitimate client to the destination's origin protocol, and how that can be abused to bypass application-layer expectations. #### 9.2.2 Origin Protocol Trust and Client Role Abuse -In addition to the message delivery and origin trust assumption, the exit -node also initiates a client-side connection to the origin protocol instance -at the destination. From the destination's perspective, this appears -indistinguishable from a conventional peer connection, and the exit is accepted -as a legitimate peer. +In addition to the message delivery and origin trust assumption, the exit node also initiates a client-side connection to the origin protocol instance at the destination. +From the destination's perspective, this appears indistinguishable from a conventional peer connection, and the exit is accepted as a legitimate peer. -As a result, any protocol-level safeguards and integrity checks are applied -to the exit node as well. However, since the exit node is not a verifiable peer -and may open fresh connections at will, such protections are limited in their -effectiveness. A malicious exit may repeatedly initiate new connections, send -well-formed fabricated messages and circumvent any peer scoring mechanisms by -reconnecting. These messages are indistinguishable from legitimate peer messages -from the destination’s point of view. +As a result, any protocol-level safeguards and integrity checks are applied to the exit node as well. +However, since the exit node is not a verifiable peer and may open fresh connections at will, such protections are limited in their effectiveness. +A malicious exit may repeatedly initiate new connections, send well-formed fabricated messages and circumvent any peer scoring mechanisms by reconnecting. +These messages are indistinguishable from legitimate peer messages from the destination's point of view. -This class of attack is distinct from basic message tampering. Even if the -message content is well-formed and semantically valid, the exit’s role as an -unaccountable client allows it to bypass application-level assumptions about -peer behavior. This results in protocol misuse, targeted disruption, or -spoofed message injection that the destination cannot attribute. +This class of attack is distinct from basic message tampering. +Even if the message content is well-formed and semantically valid, the exit's role as an unaccountable client allows it to bypass application-level assumptions about peer behavior. +This results in protocol misuse, targeted disruption, or spoofed message injection that the destination cannot attribute. -Despite these limitations, this model is compatible with legacy protocols and -destinations that do not support the Mix Protocol. It allows applications to -preserve sender anonymity without requiring any participation from the -recipient. +Despite these limitations, this model is compatible with legacy protocols and destinations that do not support the Mix Protocol. +It allows applications to preserve sender anonymity without requiring any participation from the recipient. -However, in scenarios that demand stronger end-to-end guarantees—such as -verifiable message delivery, origin authentication, or control over -client access—it may be beneficial for the destination itself to operate -a Mix instance. This alternative model is described in the next subsection. +However, in scenarios that demand stronger end-to-end guarantees—such as verifiable message delivery, origin authentication, or control over client access—it may be beneficial for the destination itself to operate a Mix instance. +This alternative model is described in the next subsection. ### 9.3 Destination as Final Hop -In some deployments, it may be desirable for the destination node to -participate in the Mix Protocol directly. In this model, the destination -operates its own Mix instance and is selected as the final node in the mix -path. The decrypted message is then delivered by the Mix Exit Layer directly to the -destination's local origin protocol instance, without relying on a separate -exit node. +In some deployments, it may be desirable for the destination node to participate in the Mix Protocol directly. +In this model, the destination operates its own Mix instance and is selected as the final node in the mix path. +The decrypted message is then delivered by the Mix Exit Layer directly to the destination's local origin protocol instance, without relying on a separate exit node. -From a security standpoint, this model provides end-to-end integrity -guarantees. It removes the trust assumption on an external exit. The message is -decrypted and delivered entirely within the destination node, eliminating the -risk of tampering during the final delivery step. The response, if used, is -also encrypted and returned by the destination itself, avoiding reliance on a -third-party node to apply the reply key. +From a security standpoint, this model provides end-to-end integrity guarantees. +It removes the trust assumption on an external exit. +The message is decrypted and delivered entirely within the destination node, eliminating the risk of tampering during the final delivery step. +The response, if used, is also encrypted and returned by the destination itself, avoiding reliance on a third-party node to apply the reply key. -This model also avoids client role abuse. Since the Mix Exit Layer delivers the -message locally, the destination need not accept arbitrary inbound connections -from external clients. This removes the risk of an adversarial exit posing as -a peer and injecting protocol-compliant but unauthorized messages. +This model also avoids client role abuse. +Since the Mix Exit Layer delivers the message locally, the destination need not accept arbitrary inbound connections from external clients. +This removes the risk of an adversarial exit posing as a peer and injecting protocol-compliant but unauthorized messages. This approach does require the destination to support the Mix Protocol. -However, this requirement can be minimized by supporting a lightweight mode in -which the destination only sends and receives messages via Mix, without -participating in message routing for other nodes. This is similar to the model -adopted by Waku, where edge nodes are not required to relay traffic but still -interact with the network. In practice, this tradeoff is often acceptable. +However, this requirement can be minimized by supporting a lightweight mode in which the destination only sends and receives messages via Mix, without participating in message routing for other nodes. +This is similar to the model adopted by Waku, where edge nodes are not required to relay traffic but still interact with the network. +In practice, this tradeoff is often acceptable. -The core Mix Protocol does not mandate destination participation. However, -implementations MAY support this model as an optional mode for use in -deployments that require stronger end-to-end security guarantees. The discovery -mechanism MAY include a flag to advertise support for routing versus -receive-only participation. Additional details on discovery configurations are -out of scope for this specification. +The core Mix Protocol does not mandate destination participation. +However, implementations MAY support this model as an optional mode for use in deployments that require stronger end-to-end security guarantees. +The discovery mechanism MAY include a flag to advertise support for routing versus receive-only participation. +Additional details on discovery configurations are out of scope for this specification. -This trust model is not required for interoperability, but is recommended -when assessing deployment-specific threat models, especially in protocols that -require message integrity or authenticated replies. +This trust model is not required for interoperability, but is recommended when assessing deployment-specific threat models, especially in protocols that require message integrity or authenticated replies. ### 9.4 Known Protocol Limitations -The Mix Protocol provides strong sender anonymity and metadata protection -guarantees within the mix network. However, it does not address all classes of -network-level disruption or application-layer abuse. This section outlines -known limitations that deployments MUST consider when -evaluating system resilience and reliability. +The Mix Protocol provides strong sender anonymity and metadata protection guarantees within the mix network. +However, it does not address all classes of network-level disruption or application-layer abuse. +This section outlines known limitations that deployments MUST consider when evaluating system resilience and reliability. #### 9.4.1 Undetectable Node Misbehavior -The Mix Protocol in its current version does not include mechanisms to detect -or attribute misbehavior by mix nodes. Since Sphinx packets are unlinkable and -routing is stateless, malicious or faulty nodes may delay, drop, or selectively -forward packets without detection. +The Mix Protocol in its current version does not include mechanisms to detect or attribute misbehavior by mix nodes. +Since Sphinx packets are unlinkable and routing is stateless, malicious or faulty nodes may delay, drop, or selectively forward packets without detection. -This behavior is indistinguishable from benign network failure. There is no -native support for feedback, acknowledgment, or proof-of-relay. As a result, -unreliable nodes cannot be penalized or excluded based on observed reliability. +This behavior is indistinguishable from benign network failure. +There is no native support for feedback, acknowledgment, or proof-of-relay. +As a result, unreliable nodes cannot be penalized or excluded based on observed reliability. -Future versions may explore accountability mechanisms. For now, deployments MAY -improve robustness by sending each packet along multiple paths as defined in -[Section X.X], but MUST treat message loss as a possibility. +Future versions may explore accountability mechanisms. +For now, deployments MAY improve robustness by sending each packet along multiple paths as defined in [Section X.X], but MUST treat message loss as a possibility. #### 9.4.2 No Built-in Retry or Acknowledgment -The Mix protocol does not support retransmission, delivery acknowledgments, -or automated fallback logic. Each message is sent once and routed -independently through the mixnet. If a message is lost or a node becomes -unavailable, recovery is the responsibility of the top-level application. +The Mix protocol does not support retransmission, delivery acknowledgments, or automated fallback logic. +Each message is sent once and routed independently through the mixnet. +If a message is lost or a node becomes unavailable, recovery is the responsibility of the top-level application. -Single-Use Reply Blocks (SURBs) (defined in Section[X.X]) enable destinations to -send responses back to the sender via a fresh mix path. However, SURBs are -optional, and their usage for acknowledgments or retries must be coordinated by -the application. +Single-Use Reply Blocks (SURBs) (defined in Section[X.X]) enable destinations to send responses back to the sender via a fresh mix path. +However, SURBs are optional, and their usage for acknowledgments or retries must be coordinated by the application. -Applications using the Mix Protocol MUST treat delivery as probabilistic. To -improve reliability, the sender MAY: +Applications using the Mix Protocol MUST treat delivery as probabilistic. +To improve reliability, the sender MAY: - Use parallel transmission across `D` disjoint paths. -- Estimate end-to-end delay bounds based on chosen per-hop delays (defined in - [Section 6.2](#62-delay-strategy)), and retry using different paths if - a response is not received within the expected window. +- Estimate end-to-end delay bounds based on chosen per-hop delays (defined in [Section 6.2](#62-delay-strategy)), and retry using different paths if a response is not received within the expected window. -These strategies MUST be implemented at the origin protocol layer or through -Mix integration logic and are not enforced by the Mix Protocol itself. +These strategies MUST be implemented at the origin protocol layer or through Mix integration logic and are not enforced by the Mix Protocol itself. #### 9.4.3 No Sybil Resistance The Mix Protocol does not include any built-in defenses against Sybil attacks. -All nodes that support the protocol and are discoverable via peer discovery -are equally eligible for path selection. An adversary that operates a large -number of Sybil nodes may be selected into mix paths more often than expected, -increasing the likelihood of partial or full path compromise. +All nodes that support the protocol and are discoverable via peer discovery are equally eligible for path selection. +An adversary that operates a large number of Sybil nodes may be selected into mix paths more often than expected, increasing the likelihood of partial or full path compromise. -In the worst case, if an adversary controls a significant fraction of nodes -(_e.g.,_ one-third of the network), the probability that a given path includes -only adversarial nodes increases sharply. This raises the risk of -deanonymization through end-to-end traffic correlation or timing analysis. +In the worst case, if an adversary controls a significant fraction of nodes (_e.g.,_ one-third of the network), the probability that a given path includes only adversarial nodes increases sharply. +This raises the risk of deanonymization through end-to-end traffic correlation or timing analysis. -Deployments concerned with Sybil resistance MAY implement passive defenses -such as minimum path length constraints. More advanced mitigations such as -stake-based participation or resource proofs typically require some form of -trusted setup or blockchain-based coordination. +Deployments concerned with Sybil resistance MAY implement passive defenses such as minimum path length constraints. +More advanced mitigations such as stake-based participation or resource proofs typically require some form of trusted setup or blockchain-based coordination. -Such defenses are out of scope in the current version of the Mix Protocol, -but are critical to ensuring anonymity at scale and may be explored in future -iterations. +Such defenses are out of scope in the current version of the Mix Protocol, but are critical to ensuring anonymity at scale and may be explored in future iterations. #### 9.4.4 Vulnerability to Denial-of-Service Attacks -The Mix Protocol does not provide built-in defenses against denial-of-service -(DoS) attacks targeting mix nodes. A malicious mix node may generate -a high volume of valid Sphinx packets to exhaust computational, memory, or -bandwidth resources along random paths through the network. +The Mix Protocol does not provide built-in defenses against denial-of-service (DoS) attacks targeting mix nodes. +A malicious mix node may generate a high volume of valid Sphinx packets to exhaust computational, memory, or bandwidth resources along random paths through the network. -This risk stems from the protocol’s stateless and sender-anonymous design. -Mix nodes process each packet independently and cannot distinguish honest users -from attackers. There is no mechanism to attribute packets, limit per-sender -usage, or apply network-wide fairness constraints. +This risk stems from the protocol's stateless and sender-anonymous design. +Mix nodes process each packet independently and cannot distinguish honest users from attackers. +There is no mechanism to attribute packets, limit per-sender usage, or apply network-wide fairness constraints. -Application-level defenses—such as PoW, VDFs, and RLNs (defined in -[Section 6.3](#63-spam-protection)) to protect destination endpoints— -do not address abuse _within_ the mixnet. Mix nodes remain vulnerable to -volumetric attacks even when destinations are protected. +Application-level defenses—such as PoW, VDFs, and RLNs (defined in [Section 6.3](#63-spam-protection)) to protect destination endpoints—do not address abuse _within_ the mixnet. +Mix nodes remain vulnerable to volumetric attacks even when destinations are protected. -While the Mix Protocol includes safeguards such as layered encryption, per-hop -integrity checks, and fixed-size headers, these primarily defend against -tagging attacks and structurally invalid or malformed traffic. The Sphinx packet -format also enforces a maximum path length $(L \leq r)$, which prevents infinite -loops or excessively long paths being embedded. However, these protections do not -prevent adversaries from injecting large volumes of short, well-formed messages to -exhaust mix node resources. +While the Mix Protocol includes safeguards such as layered encryption, per-hop integrity checks, and fixed-size headers, these primarily defend against tagging attacks and structurally invalid or malformed traffic. +The Sphinx packet format also enforces a maximum path length $(L \leq r)$, which prevents infinite loops or excessively long paths being embedded. +However, these protections do not prevent adversaries from injecting large volumes of short, well-formed messages to exhaust mix node resources. -DoS protection—such as admission control, rate-limiting, or resource-bound -access—MUST be implemented outside the core protocol. Any such mechanism MUST -preserve sender unlinkability and SHOULD be evaluated carefully to avoid -introducing correlation risks. +DoS protection—such as admission control, rate-limiting, or resource-bound access—MUST be implemented outside the core protocol. +Any such mechanism MUST preserve sender unlinkability and SHOULD be evaluated carefully to avoid introducing correlation risks. -Defending against large-scale DoS attacks is considered a deployment-level -responsibility and is out of scope for this specification. +Defending against large-scale DoS attacks is considered a deployment-level responsibility and is out of scope for this specification. From 4f54254706666e373b5987901d974dc40f109293 Mon Sep 17 00:00:00 2001 From: Prem Chaitanya Prathi Date: Fri, 12 Dec 2025 14:59:14 +0530 Subject: [PATCH 4/6] fix format errors in math sections for mix rfc (#225) --- vac/raw/mix.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/vac/raw/mix.md b/vac/raw/mix.md index e10a255..2052d65 100644 --- a/vac/raw/mix.md +++ b/vac/raw/mix.md @@ -763,7 +763,7 @@ The construction MUST proceed as follows: \begin{array}{l} Φ_i = \mathrm{AES\text{-}CTR}'_i\bigl(Φ_{\mathrm{aes\_key}_{i-1}}, Φ_{\mathrm{iv}_{i-1}}, Φ_{i-1} \mid 0_{(t+1)κ} \bigr),\; \; \; - \text{where notation $0_x$ defines the string of $0$ bits of length $x$.} + \text{where notation } 0_x \text{ defines the string of } 0 \text{ bits of length } x\text{.} \end{array} `$ @@ -814,9 +814,9 @@ The construction MUST proceed as follows: \begin{array}{l} β_i = \mathrm{AES\text{-}CTR}\bigl(β_{\mathrm{aes\_key}_i}, β_{\mathrm{iv}_i}, \mathrm{addr}_{i+1} \mid \mathrm{delay}_i - \mid γ_{i+1} \mid β_{i+1 \, [0 \ldots (r(t+1) - t)κ - 1]} \bigr),\; \; \; - \text{where notation $X_{[a \ldots b]}$ denotes the substring of $X$ - from byte offset $a$ to $b$, inclusive, using zero-based indexing.} + \mid γ_{i+1} \mid β_{i+1 \, [0 \ldots (r(t+1) - t)κ - 1]} \bigr),\\ + \text{where notation } X_{[a \ldots b]} \text{ denotes the substring of } X + \text{ from byte offset } a \text{ to } b\text{, inclusive, using zero-based indexing.} \end{array} `$ @@ -1055,7 +1055,7 @@ Once the node determines its role as an intermediary following the steps in [Sec $` \begin{array}{l} - β' = B_{[(t + 1)κ\ldots(r(t +1 ) + t + 2)\kappa - 1]} + β' = B_{[(t + 1)κ\ldots(r(t +1 ) + t + 2)κ - 1]} \end{array} `$ @@ -1142,8 +1142,8 @@ Once the node determines its role as an exit following the steps in [Section 8.6 $` \begin{array}{l} m = δ'_{[κ\ldots]},\; \; \; - \text{where notation $X_{[a \ldots]}$ denotes the substring of $X$ - from byte offset $a$ to the end of the string using zero-based indexing.} + \text{where notation } X_{[a \ldots]} \text{ denotes the substring of } X + \text{ from byte offset } a \text{ to the end of the string using zero-based indexing.} \end{array} `$ From b2f35644a4ffd6ec871d1a0e73c62dbffedb93e2 Mon Sep 17 00:00:00 2001 From: Cofson <41572590+Cofson@users.noreply.github.com> Date: Fri, 12 Dec 2025 12:10:02 +0100 Subject: [PATCH 5/6] Improved codex/raw/codex-block-exchange.md file (#215) Improved codex-block-exchange.md file in codex/raw folder --- codex/raw/codex-block-exchange.md | 1236 ++++++++++++++++++++++++++++- 1 file changed, 1233 insertions(+), 3 deletions(-) diff --git a/codex/raw/codex-block-exchange.md b/codex/raw/codex-block-exchange.md index 348caea..39097f4 100644 --- a/codex/raw/codex-block-exchange.md +++ b/codex/raw/codex-block-exchange.md @@ -6,8 +6,20 @@ category: Standards Track tags: codex, block-exchange, p2p, data-distribution editor: Codex Team contributors: + - Filip Dimitrijevic --- +## Specification Status + +This specification contains a mix of: + +- **Verified protocol elements**: Core message formats, protobuf structures, and addressing modes confirmed from implementation +- **Design specifications**: Payment flows, state machines, and negotiation strategies representing intended behavior +- **Recommended values**: Protocol limits and timeouts that serve as guidelines (actual implementations may vary) +- **Pending verification**: Some technical details (e.g., multicodec 0xCD02) require further validation + +Sections marked with notes indicate areas where implementation details may differ from this specification. + ## Abstract The Block Exchange (BE) is a core Codex component responsible for @@ -38,6 +50,9 @@ document are to be interpreted as described in | **Block Delivery** | Transmission of block data from one peer to another | | **Block Presence** | Indicator of whether peer has requested block | | **Merkle Proof** | Proof verifying dataset block position correctness | +| **CodexProof** | Codex-specific Merkle proof format verifying a block's position within a dataset tree | +| **Stream** | Bidirectional libp2p communication channel between two peers for exchanging messages | +| **Peer Context Store** | Internal data structure tracking active peer connections, their WantLists, and exchange state | | **CID** | Content Identifier - hash-based identifier for content | | **Multicodec** | Self-describing format identifier for data encoding | | **Multihash** | Self-describing hash format | @@ -115,10 +130,40 @@ following specifications: | Property | Value | Description | |----------|-------|-------------| | Default Block Size | 64 KiB | Standard size for data blocks | -| Multicodec | `codex-block` (0xCD02) | Format identifier | +| Maximum Block Size | 100 MiB | Upper limit for block data field | +| Multicodec | `codex-block` (0xCD02)* | Format identifier | | Multihash | `sha2-256` (0x12) | Hash algorithm for addressing | | Padding Requirement | Zero-padding | Incomplete final blocks padded | +**Note:** *The multicodec value 0xCD02 is not currently registered in the official [multiformats multicodec table](https://github.com/multiformats/multicodec/blob/master/table.csv). This may be a reserved/private code pending official registration. + +### Protocol Limits + +To ensure network stability and prevent resource exhaustion, implementations +SHOULD enforce reasonable limits. The following are **recommended values** +(actual implementation limits may vary): + +| Limit | Recommended Value | Description | +|-------|-------------------|-------------| +| **Maximum Block Size** | 100 MiB | Maximum size of block data in BlockDelivery | +| **Maximum WantList Size** | 1000 entries | Maximum entries per WantList message | +| **Maximum Concurrent Requests** | 256 per peer | Maximum simultaneous block requests per peer | +| **Stream Timeout** | 60 seconds | Idle stream closure timeout | +| **Request Timeout** | 300 seconds | Maximum time to fulfill a block request | +| **Maximum Message Size** | 105 MiB | Maximum total message size (protobuf) | +| **Maximum Pending Bytes** | 10 GiB | Maximum pending data per peer connection | + +**Note:** These values are **not verified from implementation** and serve as +reasonable guidelines. Actual implementations MAY use different limits based +on their resource constraints and deployment requirements. + +**Enforcement:** + +- Implementations MUST reject messages exceeding their configured size limits +- Implementations SHOULD track per-peer request counts +- Implementations SHOULD close streams exceeding configured timeout limits +- Implementations MAY implement stricter or more lenient limits based on local resources + ## Service Interface The Block Exchange module exposes two core primitives for @@ -183,6 +228,103 @@ identifier: /codex/blockexc/1.0.0 ``` +### Version Negotiation + +The protocol version is negotiated through libp2p's multistream-select +protocol during connection establishment. The following describes standard +libp2p version negotiation behavior; actual Codex implementation details +may vary. + +#### Protocol Versioning + +**Version Format**: `/codex/blockexc/..` + +- **Major version**: Incompatible protocol changes +- **Minor version**: Backward-compatible feature additions +- **Patch version**: Backward-compatible bug fixes + +**Current Version**: `1.0.0` + +#### Version Negotiation Process + +```text +1. Initiator opens stream +2. Initiator proposes: "/codex/blockexc/1.0.0" +3. Responder checks supported versions +4. If supported: + Responder accepts: "/codex/blockexc/1.0.0" + → Connection established +5. If not supported: + Responder rejects with: "na" (not available) + → Try fallback version or close connection +``` + +#### Compatibility Rules + +**Major Version Compatibility:** + +- Major version `1.x.x` is incompatible with `2.x.x` +- Nodes MUST support only their major version +- Cross-major-version communication requires protocol upgrade + +**Minor Version Compatibility:** + +- Version `1.1.0` MUST be backward compatible with `1.0.0` +- Newer minors MAY include optional features +- Older nodes ignore unknown message fields (protobuf semantics) + +**Patch Version Compatibility:** + +- All patches within same minor version are fully compatible +- Patches fix bugs without changing protocol behavior + +#### Multi-Version Support + +Implementations MAY support multiple protocol versions simultaneously: + +```text +Supported protocols (in preference order): + 1. /codex/blockexc/1.2.0 (preferred, latest features) + 2. /codex/blockexc/1.1.0 (fallback, stable) + 3. /codex/blockexc/1.0.0 (legacy support) +``` + +**Negotiation Strategy:** + +1. Propose highest supported version first +2. If rejected, try next lower version +3. If all rejected, connection fails +4. Track peer's supported version for future connections + +#### Feature Detection + +For optional features within same major.minor version: + +```text +Method 1: Message field presence + - Send message with optional field + - Peer ignores if not supported (protobuf default) + +Method 2: Capability exchange (future extension) + - Exchange capability bitmask in initial message + - Enable features only if both peers support +``` + +#### Version Upgrade Path + +**Backward Compatibility:** + +- New versions MUST handle messages from older versions +- Unknown message fields silently ignored +- Unknown WantList flags ignored +- Unknown BlockPresence types treated as DontHave + +**Forward Compatibility:** + +- Older versions MAY ignore new message types +- Critical features require major version bump +- Optional features use minor version bump + ### Connection Model The protocol operates over libp2p streams. @@ -204,6 +346,421 @@ The protocol handles peer lifecycle events: - **Peer Dropped**: When a peer connection fails, it is removed from the active set +### Message Flow Examples + +This section illustrates typical message exchange sequences for common +block exchange scenarios. + +#### Example 1: Standalone Block Request + +**Scenario**: Node A requests a standalone block from Node B + +```text +Node A Node B + | | + |--- Message(wantlist) ------------------>| + | wantlist.entries[0]: | + | address.cid = QmABC123 | + | wantType = wantBlock | + | priority = 0 | + | | + |<-- Message(blockPresences, payload) ----| + | blockPresences[0]: | + | address.cid = QmABC123 | + | type = presenceHave | + | payload[0]: | + | cid = QmABC123 | + | data = <64 KiB block data> | + | address.cid = QmABC123 | + | | +``` + +**Steps:** + +1. Node A sends WantList requesting block with `wantType = wantBlock` +2. Node B checks local storage, finds block +3. Node B responds with BlockPresence confirming availability +4. Node B includes BlockDelivery with actual block data +5. Node A verifies CID matches SHA256(data) +6. Node A stores block locally + +#### Example 2: Dataset Block Request with Merkle Proof + +**Scenario**: Node A requests a dataset block from Node B + +```text +Node A Node B + | | + |--- Message(wantlist) ------------------>| + | wantlist.entries[0]: | + | address.leaf = true | + | address.treeCid = QmTree456 | + | address.index = 42 | + | wantType = wantBlock | + | | + |<-- Message(payload) ---------------------| + | payload[0]: | + | cid = QmBlock789 | + | data = <64 KiB zero-padded data> | + | address.leaf = true | + | address.treeCid = QmTree456 | + | address.index = 42 | + | proof = | + | | +``` + +**Steps:** + +1. Node A sends WantList for dataset block at specific index +2. Node B locates block in dataset +3. Node B generates CodexProof for block position in Merkle tree +4. Node B delivers block with proof +5. Node A verifies proof against treeCid +6. Node A verifies block data integrity +7. Node A stores block with dataset association + +#### Example 3: Block Presence Check (wantHave) + +**Scenario**: Node A checks if Node B has a block without requesting full data + +```text +Node A Node B + | | + |--- Message(wantlist) ------------------>| + | wantlist.entries[0]: | + | address.cid = QmCheck999 | + | wantType = wantHave | + | sendDontHave = true | + | | + |<-- Message(blockPresences) -------------| + | blockPresences[0]: | + | address.cid = QmCheck999 | + | type = presenceHave | + | price = 0x00 (free) | + | | +``` + +**Steps:** + +1. Node A sends WantList with `wantType = wantHave` +2. Node B checks local storage without loading block data +3. Node B responds with BlockPresence only (no payload) +4. Node A updates peer availability map +5. If Node A decides to request, sends new WantList with `wantType = wantBlock` + +#### Example 4: Block Not Available + +**Scenario**: Node A requests block Node B doesn't have + +```text +Node A Node B + | | + |--- Message(wantlist) ------------------>| + | wantlist.entries[0]: | + | address.cid = QmMissing111 | + | wantType = wantBlock | + | sendDontHave = true | + | | + |<-- Message(blockPresences) -------------| + | blockPresences[0]: | + | address.cid = QmMissing111 | + | type = presenceDontHave | + | | +``` + +**Steps:** + +1. Node A requests block with `sendDontHave = true` +2. Node B checks storage, block not found +3. Node B sends BlockPresence with `presenceDontHave` +4. Node A removes Node B from candidates for this block +5. Node A queries discovery service for alternative peers + +#### Example 5: WantList Cancellation + +**Scenario**: Node A cancels a previous block request + +```text +Node A Node B + | | + |--- Message(wantlist) ------------------>| + | wantlist.entries[0]: | + | address.cid = QmCancel222 | + | cancel = true | + | | +``` + +**Steps:** + +1. Node A sends WantList entry with `cancel = true` +2. Node B removes block request from peer's want queue +3. Node B stops any pending block transfer for this address +4. No response message required for cancellation + +#### Example 6: Delta WantList Update + +**Scenario**: Node A adds requests to existing WantList + +```text +Node A Node B + | | + |--- Message(wantlist) ------------------>| + | wantlist.full = false | + | wantlist.entries[0]: | + | address.cid = QmNew1 | + | wantType = wantBlock | + | wantlist.entries[1]: | + | address.cid = QmNew2 | + | wantType = wantBlock | + | | +``` + +**Steps:** + +1. Node A sends WantList with `full = false` (delta update) +2. Node B merges entries with existing WantList for Node A +3. Node B begins processing new requests +4. Previous WantList entries remain active + +### Sequence Diagrams + +These diagrams illustrate the complete flow of block exchange operations +including service interface, peer discovery, and network protocol interactions. + +#### Complete Block Request Flow + +The protocol supports two strategies for WantBlock requests, +each with different trade-offs. +Implementations may choose the strategy based on network conditions, +peer availability, and resource constraints. + +##### Strategy 1: Parallel Request (Low Latency) + +In this strategy, the requester sends `wantType = wantBlock` to all +discovered peers simultaneously. +This minimizes latency as the first peer to respond with the block +data wins, but it wastes bandwidth since multiple peers may send +the same block data. + +**Trade-offs:** + +- **Pro**: Lowest latency - block arrives as soon as any peer can deliver it +- **Pro**: More resilient to slow or unresponsive peers +- **Con**: Bandwidth-wasteful - multiple peers may send duplicate data +- **Con**: Higher network overhead for the requester +- **Best for**: Time-critical data retrieval, unreliable networks + +```mermaid +sequenceDiagram + participant Client + participant BlockExchange + participant LocalStore + participant Discovery + participant PeerA + participant PeerB + participant PeerC + + Client->>BlockExchange: requestBlock(address) + BlockExchange->>LocalStore: checkBlock(address) + LocalStore-->>BlockExchange: Not found + + BlockExchange->>Discovery: findPeers(address) + Discovery-->>BlockExchange: [PeerA, PeerB, PeerC] + + par Send wantBlock to all peers + BlockExchange->>PeerA: Message(wantlist: wantBlock) + BlockExchange->>PeerB: Message(wantlist: wantBlock) + BlockExchange->>PeerC: Message(wantlist: wantBlock) + end + + Note over PeerA,PeerC: All peers start preparing block data + + PeerB-->>BlockExchange: Message(payload: BlockDelivery) + Note over BlockExchange: First response wins + + BlockExchange->>BlockExchange: Verify block + BlockExchange->>LocalStore: Store block + + par Cancel requests to other peers + BlockExchange->>PeerA: Message(wantlist: cancel) + BlockExchange->>PeerC: Message(wantlist: cancel) + end + + Note over PeerA,PeerC: May have already sent data (wasted bandwidth) + + BlockExchange-->>Client: Return block +``` + +##### Strategy 2: Two-Phase Discovery (Bandwidth Efficient) + +In this strategy, the requester first sends `wantType = wantHave` to +discover which peers have the block, then sends `wantType = wantBlock` +only to a single selected peer. +This conserves bandwidth but adds an extra round-trip of latency. + +**Trade-offs:** + +- **Pro**: Bandwidth-efficient - only one peer sends block data +- **Pro**: Enables price comparison before committing to a peer +- **Pro**: Allows selection based on peer reputation or proximity +- **Con**: Higher latency due to extra round-trip for presence check +- **Con**: Selected peer may become unavailable between phases +- **Best for**: Large blocks, paid content, bandwidth-constrained networks + +```mermaid +sequenceDiagram + participant Client + participant BlockExchange + participant LocalStore + participant Discovery + participant PeerA + participant PeerB + participant PeerC + + Client->>BlockExchange: requestBlock(address) + BlockExchange->>LocalStore: checkBlock(address) + LocalStore-->>BlockExchange: Not found + + BlockExchange->>Discovery: findPeers(address) + Discovery-->>BlockExchange: [PeerA, PeerB, PeerC] + + Note over BlockExchange: Phase 1: Discovery + + par Send wantHave to all peers + BlockExchange->>PeerA: Message(wantlist: wantHave) + BlockExchange->>PeerB: Message(wantlist: wantHave) + BlockExchange->>PeerC: Message(wantlist: wantHave) + end + + PeerA-->>BlockExchange: BlockPresence(presenceDontHave) + PeerB-->>BlockExchange: BlockPresence(presenceHave, price=X) + PeerC-->>BlockExchange: BlockPresence(presenceHave, price=Y) + + BlockExchange->>BlockExchange: Select best peer (PeerB: lower price) + + Note over BlockExchange: Phase 2: Retrieval + + BlockExchange->>PeerB: Message(wantlist: wantBlock) + PeerB-->>BlockExchange: Message(payload: BlockDelivery) + + BlockExchange->>BlockExchange: Verify block + BlockExchange->>LocalStore: Store block + BlockExchange-->>Client: Return block +``` + +##### Hybrid Approach + +Implementations MAY combine both strategies: + +1. Use two-phase discovery for large blocks or paid content +2. Use parallel requests for small blocks or time-critical data +3. Adaptively switch strategies based on network conditions + +```mermaid +flowchart TD + A[Block Request] --> B{Block Size?} + B -->|Small < 64 KiB| C[Parallel Strategy] + B -->|Large >= 64 KiB| D{Paid Content?} + D -->|Yes| E[Two-Phase Discovery] + D -->|No| F{Network Condition?} + F -->|Reliable| E + F -->|Unreliable| C + C --> G[Return Block] + E --> G +``` + +#### Dataset Block Verification Flow + +```mermaid +sequenceDiagram + participant Requester + participant Provider + participant Verifier + + Requester->>Provider: WantList(leaf=true, treeCid, index) + Provider->>Provider: Load block at index + Provider->>Provider: Generate CodexProof + Provider->>Requester: BlockDelivery(data, proof) + + Requester->>Verifier: Verify proof + + alt Proof valid + Verifier-->>Requester: Valid + Requester->>Requester: Verify CID + alt CID matches + Requester->>Requester: Store block + Requester-->>Requester: Success + else CID mismatch + Requester->>Requester: Reject block + Requester->>Provider: Disconnect + end + else Proof invalid + Verifier-->>Requester: Invalid + Requester->>Requester: Reject block + Requester->>Provider: Disconnect + end +``` + +#### Payment Flow with State Channels + +```mermaid +sequenceDiagram + participant Buyer + participant Seller + participant StateChannel + + Buyer->>Seller: Message(wantlist) + Seller->>Seller: Check block availability + Seller->>Buyer: BlockPresence(price) + + alt Buyer accepts price + Buyer->>StateChannel: Create update + StateChannel-->>Buyer: Signed state + Buyer->>Seller: Message(payment: StateChannelUpdate) + Seller->>StateChannel: Verify update + + alt Payment valid + StateChannel-->>Seller: Valid + Seller->>Buyer: BlockDelivery(data) + Buyer->>Buyer: Verify block + Buyer->>StateChannel: Finalize + else Payment invalid + StateChannel-->>Seller: Invalid + Seller->>Buyer: BlockPresence(price) + end + else Buyer rejects price + Buyer->>Seller: Message(wantlist.cancel) + end +``` + +#### Peer Lifecycle Management + +```mermaid +sequenceDiagram + participant Network + participant BlockExchange + participant PeerStore + participant Peer + + Network->>BlockExchange: PeerJoined(Peer) + BlockExchange->>PeerStore: AddPeer(Peer) + BlockExchange->>Peer: Open stream + + loop Active exchange + BlockExchange->>Peer: Message(wantlist/payload) + Peer->>BlockExchange: Message(payload/presence) + end + + alt Graceful disconnect + Peer->>BlockExchange: Close stream + BlockExchange->>PeerStore: RemovePeer(Peer) + else Connection failure + Network->>BlockExchange: PeerDropped(Peer) + BlockExchange->>PeerStore: RemovePeer(Peer) + BlockExchange->>BlockExchange: Requeue pending requests + end +``` + ### Message Format All messages use Protocol Buffers encoding for serialization. @@ -215,6 +772,7 @@ single message. ```protobuf message Message { Wantlist wantlist = 1; + // Field 2 reserved for future use repeated BlockDelivery payload = 3; repeated BlockPresence blockPresences = 4; int32 pendingBytes = 5; @@ -226,12 +784,28 @@ message Message { **Fields:** - `wantlist`: Block requests from the sender +- Field 2: Reserved (unused, see note below) - `payload`: Block deliveries (actual block data) - `blockPresences`: Availability indicators for requested blocks - `pendingBytes`: Number of bytes pending delivery - `account`: Account information for micropayments - `payment`: State channel update for payment processing +**Note on Missing Field 2:** + +Field number 2 is intentionally skipped in the Message protobuf definition. +This is a common protobuf practice for several reasons: + +- **Protocol Evolution**: Field 2 may have been used in earlier versions and + removed, with the field number reserved to prevent reuse +- **Forward Compatibility**: Reserving field numbers ensures old clients can + safely ignore new fields +- **Implementation History**: May have been used during development and removed + before final release + +The gap does not affect protocol operation. Protobuf field numbers need not be +sequential, and skipping numbers is standard practice for protocol evolution. + #### Block Address The BlockAddress structure supports both standalone and dataset @@ -295,7 +869,7 @@ message Wantlist { **Entry Fields:** - `address`: The block being requested -- `priority`: Request priority (currently always 0) +- `priority`: Request priority (currently always 0, reserved for future use) - `cancel`: If true, cancels a previous want for this block - `wantType`: Specifies whether full block or presence is desired - `wantHave (1)`: Only check if peer has the block @@ -303,6 +877,34 @@ message Wantlist { - `sendDontHave`: If true, peer should respond even if it doesn't have the block +**Priority Field Clarification:** + +The `priority` field is currently fixed at `0` in all implementations and is +reserved for future protocol extensions. Originally intended for request +prioritization, this feature is not yet implemented. + +**Current Behavior:** + +- All WantList entries use `priority = 0` +- Implementations MUST accept priority values but MAY ignore them +- Blocks are processed in order received, not by priority + +**Future Extensions:** + +The priority field is reserved for: + +- **Bandwidth Management**: Higher priority blocks served first during congestion +- **Time-Critical Data**: Urgent blocks (e.g., recent dataset indices) prioritized +- **Fair Queueing**: Priority-based scheduling across multiple peers +- **QoS Tiers**: Different service levels based on payment/reputation + +**Implementation Notes:** + +- Senders SHOULD set `priority = 0` for compatibility +- Receivers MUST NOT reject messages with non-zero priority +- Future protocol versions may activate priority-based scheduling +- When activated, higher priority values = higher priority (0 = lowest) + **WantList Fields:** - `entries`: List of block requests @@ -370,7 +972,59 @@ message BlockPresence { - `address`: The block address being referenced - `type`: Whether the peer has the block or not -- `price`: Price (UInt256 format) +- `price`: Price in wei (UInt256 format, see below) + +**UInt256 Price Format:** + +The `price` field encodes a 256-bit unsigned integer representing the cost in +wei (the smallest Ethereum denomination, where 1 ETH = 10^18 wei). + +**Encoding Specification:** + +- **Format**: 32 bytes, big-endian byte order +- **Type**: Unsigned 256-bit integer +- **Range**: 0 to 2^256 - 1 +- **Zero Price**: `0x0000000000000000000000000000000000000000000000000000000000000000` + (block is free) + +**Examples:** + +```text +Free (0 wei): + 0x0000000000000000000000000000000000000000000000000000000000000000 + +1 wei: + 0x0000000000000000000000000000000000000000000000000000000000000001 + +1 gwei (10^9 wei): + 0x000000000000000000000000000000000000000000000000000000003b9aca00 + +0.001 ETH (10^15 wei): + 0x00000000000000000000000000000000000000000000000000038d7ea4c68000 + +1 ETH (10^18 wei): + 0x0000000000000000000000000000000000000000000000000de0b6b3a7640000 + +Maximum (2^256 - 1): + 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +``` + +**Conversion Logic:** + +```python +# Wei to bytes (big-endian) +def wei_to_bytes(amount_wei: int) -> bytes: + return amount_wei.to_bytes(32, byteorder='big') + +# Bytes to wei +def bytes_to_wei(price_bytes: bytes) -> int: + return int.from_bytes(price_bytes, byteorder='big') + +# ETH to wei to bytes +def eth_to_price_bytes(amount_eth: float) -> bytes: + amount_wei = int(amount_eth * 10**18) + return wei_to_bytes(amount_wei) +``` #### Payment Messages @@ -388,6 +1042,250 @@ message AccountMessage { - `address`: Ethereum address for receiving payments +### Concrete Message Examples + +This section provides real-world examples of protobuf messages for different +block exchange scenarios. + +#### Example 1: Simple Standalone Block Request + +**Scenario**: Request a single standalone block + +**Protobuf (wire format representation):** + +```protobuf +Message { + wantlist: Wantlist { + entries: [ + Entry { + address: BlockAddress { + leaf: false + cid: 0x0155a0e40220b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 // CID bytes + } + priority: 0 + cancel: false + wantType: wantBlock // 0 + sendDontHave: true + } + ] + full: true + } +} +``` + +**Hex representation (sample):** + +```text +0a2e 0a2c 0a24 0001 5512 2012 20b9 4d27 +b993 4d3e 08a5 2e52 d7da 7dab fac4 84ef +e37a 5380 ee90 88f7 ace2 efcd e910 0018 +0020 0028 011201 01 +``` + +#### Example 2: Dataset Block Request + +**Scenario**: Request block at index 100 from dataset + +**Protobuf:** + +```protobuf +Message { + wantlist: Wantlist { + entries: [ + Entry { + address: BlockAddress { + leaf: true + treeCid: 0x0155a0e40220c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 // Tree CID + index: 100 + } + priority: 0 + cancel: false + wantType: wantBlock + sendDontHave: true + } + ] + full: false // Delta update + } +} +``` + +#### Example 3: Block Delivery with Proof + +**Scenario**: Provider sends dataset block with Merkle proof + +**Protobuf:** + +```protobuf +Message { + payload: [ + BlockDelivery { + cid: 0x0155a0e40220a1b2c3d4e5f6071829... // Block CID + data: <65536 bytes of block data> // 64 KiB + address: BlockAddress { + leaf: true + treeCid: 0x0155a0e40220c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 + index: 100 + } + proof: // Merkle proof data + // Contains: path indices, sibling hashes, tree height + // Format: Implementation-specific (e.g., [height][index][hash1][hash2]...[hashN]) + // Size varies by tree depth (illustrative: ~1KB for depth-10 tree) + } + ] +} +``` + +#### Example 4: Block Presence Response + +**Scenario**: Provider indicates block availability with price + +**Protobuf:** + +```protobuf +Message { + blockPresences: [ + BlockPresence { + address: BlockAddress { + leaf: false + cid: 0x0155a0e40220b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 + } + type: presenceHave // 0 + price: 0x00000000000000000000000000000000000000000000000000038d7ea4c68000 // 0.001 ETH in wei + } + ] +} +``` + +#### Example 5: Payment Message + +**Scenario**: Send payment via state channel update + +**Protobuf:** + +```protobuf +Message { + account: AccountMessage { + address: 0x742d35Cc6634C0532925a3b844200a717C48D6d9 // 20 bytes Ethereum address + } + payment: StateChannelUpdate { + update: + // Contains signed Nitro state as UTF-8 JSON string + // Example: {"channelId":"0x1234...","nonce":42,...} + } +} +``` + +#### Example 6: Multiple Operations in One Message + +**Scenario**: Combined WantList, BlockPresence, and Delivery + +**Protobuf:** + +```protobuf +Message { + wantlist: Wantlist { + entries: [ + Entry { + address: BlockAddress { + leaf: false + cid: 0x0155a0e40220... // Requesting new block + } + wantType: wantBlock + priority: 0 + cancel: false + sendDontHave: true + } + ] + full: false + } + blockPresences: [ + BlockPresence { + address: BlockAddress { + leaf: false + cid: 0x0155a0e40220... // Response to previous request + } + type: presenceHave + price: 0x00 // Free + } + ] + payload: [ + BlockDelivery { + cid: 0x0155a0e40220... // Delivering another block + data: <65536 bytes> + address: BlockAddress { + leaf: false + cid: 0x0155a0e40220... + } + } + ] + pendingBytes: 131072 // 128 KiB more data pending +} +``` + +#### Example 7: WantList Cancellation + +**Scenario**: Cancel multiple pending requests + +**Protobuf:** + +```protobuf +Message { + wantlist: Wantlist { + entries: [ + Entry { + address: BlockAddress { + leaf: false + cid: 0x0155a0e40220abc123... + } + cancel: true // Cancellation flag + }, + Entry { + address: BlockAddress { + leaf: true + treeCid: 0x0155a0e40220def456... + index: 50 + } + cancel: true + } + ] + full: false + } +} +``` + +#### CID Format Details + +**CID Structure:** + +```text +CID v1 format (multibase + multicodec + multihash): +[0x01] [0x55] [0xa0] [0xe4] [0x02] [0x20] [<32 bytes SHA256 hash>] + │ │ │ │ │ │ │ + │ │ │ │ │ │ └─ Hash digest + │ │ │ │ │ └───────── Hash length (32) + │ │ │ │ └──────────────── Hash algorithm (SHA2-256) + │ │ │ └─────────────────────── Codec size + │ │ └────────────────────────────── Codec (raw = 0x55) + │ └───────────────────────────────────── Multicodec prefix + └──────────────────────────────────────────── CID version (1) + +Actual: 0x01 55 a0 e4 02 20 +``` + +**Example Block CID Breakdown:** + +```text +Full CID: 0x0155a0e40220b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 + +Parts: + Version: 0x01 (CID v1) + Multicodec: 0x55 (raw) + Codec Size: 0xa0e402 (codex-block = 0xCD02, varint encoded)* + Hash Type: 0x20 (SHA2-256) + Hash Len: 0x12 (20) (32 bytes) + Hash: b94d27b993... (32 bytes SHA256) +``` + **State Channel Update:** ```protobuf @@ -400,6 +1298,338 @@ message StateChannelUpdate { - `update`: Nitro state channel update containing payment information +### Payment Flow and Price Negotiation + +The Block Exchange protocol integrates with Nitro state channels to enable +micropayments for block delivery. + +#### Payment Requirements + +**When Payment is Required:** + +- Blocks marked as paid content by the provider +- Provider's local policy requires payment for specific blocks +- Block size exceeds free tier threshold (implementation-defined) +- Requester has insufficient credit with provider + +**Free Blocks:** + +- Blocks explicitly marked as free (`price = 0x00`) +- Blocks exchanged between trusted peers +- Small metadata blocks (implementation-defined) + +#### Price Discovery + +**Initial Price Advertisement:** + +1. Requester sends WantList with `wantType = wantHave` +2. Provider responds with BlockPresence including `price` field +3. Price encoded as UInt256 in wei (smallest Ethereum unit) +4. Requester evaluates price against local policy + +**Price Format:** + +```text +price: bytes (32 bytes, big-endian UInt256) +Example: 0x0000000000000000000000000000000000000000000000000de0b6b3a7640000 + represents 1 ETH = 10^18 wei +``` + +#### Payment Negotiation Process + +##### Step 1: Price Quote + +```text +Requester → Provider: Message(wantlist: wantHave) +Provider → Requester: BlockPresence(type=presenceHave, price=) +``` + +##### Step 2: Payment Decision + +Requester evaluates price: + +- **Accept**: Proceed to payment +- **Reject**: Send cancellation +- **Counter**: Not supported in current protocol (future extension) + +##### Step 3: State Channel Update + +If accepted: + +```text +Requester: + 1. Load existing state channel with Provider + 2. Create new state with updated balance + 3. Sign state update + 4. Encode as JSON + +Requester → Provider: Message(payment: StateChannelUpdate(update=)) +``` + +##### Step 4: Payment Verification + +```text +Provider: + 1. Decode state channel update + 2. Verify signatures + 3. Check balance increase matches price + 4. Verify state channel validity + 5. Check nonce/sequence number + +If valid: + Provider → Requester: BlockDelivery(data, proof) +Else: + Provider → Requester: BlockPresence(price) // Retry with correct payment +``` + +##### Step 5: Delivery and Finalization + +```text +Requester: + 1. Receive and verify block + 2. Store block locally + 3. Finalize state channel update + 4. Update peer credit balance +``` + +#### Payment State Machine + +**Note:** The following state machine represents a **design specification** for +payment flow logic. Actual implementation may differ. + +```text +State: INIT + → Send wantHave + → Transition to PRICE_DISCOVERY + +State: PRICE_DISCOVERY + ← Receive BlockPresence(price) + → If price acceptable: Transition to PAYMENT_CREATION + → If price rejected: Transition to CANCELLED + +State: PAYMENT_CREATION + → Create state channel update + → Send payment message + → Transition to PAYMENT_PENDING + +State: PAYMENT_PENDING + ← Receive BlockDelivery: Transition to DELIVERY_VERIFICATION + ← Receive BlockPresence(price): Transition to PAYMENT_FAILED + +State: PAYMENT_FAILED + → Retry with corrected payment: Transition to PAYMENT_CREATION + → Abort: Transition to CANCELLED + +State: DELIVERY_VERIFICATION + → Verify block + → If valid: Transition to COMPLETED + → If invalid: Transition to DISPUTE + +State: COMPLETED + → Finalize state channel + → End + +State: CANCELLED + → Send cancellation + → End + +State: DISPUTE + → Reject block + → Dispute state channel update + → End +``` + +#### State Channel Integration + +**Account Message Usage:** + +Sent early in connection to establish payment address: + +```protobuf +Message { + account: AccountMessage { + address: 0x742d35Cc6634C0532925a3b8... // Ethereum address + } +} +``` + +**State Channel Update Format:** + +```json +{ + "channelId": "0x1234...", + "nonce": 42, + "balances": { + "0x742d35Cc...": "1000000000000000000", // Seller balance + "0x8ab5d2F3...": "500000000000000000" // Buyer balance + }, + "signatures": [ + "0x789abc...", // Buyer signature + "0x456def..." // Seller signature + ] +} +``` + +#### Error Scenarios + +**Insufficient Funds:** + +- State channel balance < block price +- Response: BlockPresence with price (retry after funding) + +**Invalid Signature:** + +- State update signature verification fails +- Response: Reject payment, close stream if repeated + +**Nonce Mismatch:** + +- State update nonce doesn't match expected sequence +- Response: Request state sync, retry with correct nonce + +**Channel Expired:** + +- State channel past expiration time +- Response: Refuse payment, request new channel creation + +## Error Handling + +The Block Exchange protocol defines error handling for common failure scenarios: + +### Verification Failures + +**Merkle Proof Verification Failure:** + +- **Condition**: CodexProof validation fails for dataset block +- **Action**: Reject block delivery, do NOT store block +- **Response**: Send BlockPresence with `presenceDontHave` for the address +- **Logging**: Log verification failure with peer ID and block address +- **Peer Management**: Track repeated failures; disconnect after threshold + +**CID Mismatch:** + +- **Condition**: SHA256 hash of block data doesn't match provided CID +- **Action**: Reject block delivery immediately +- **Response**: Close stream and mark peer as potentially malicious +- **Logging**: Log CID mismatch with peer ID and expected/actual CIDs + +### Network Failures + +**Stream Disconnection:** + +- **Condition**: libp2p stream closes unexpectedly during transfer +- **Action**: Cancel pending block requests for that peer +- **Recovery**: Attempt to request blocks from alternative peers +- **Timeout**: Wait for stream timeout (60s) before peer cleanup + +**Missing Blocks:** + +- **Condition**: Peer responds with `presenceDontHave` for requested block +- **Action**: Remove peer from candidates for this block +- **Recovery**: Query discovery service for alternative peers +- **Fallback**: If no peers have block, return error to `requestBlock` caller + +**Request Timeout:** + +- **Condition**: Block not received within request timeout (300s) +- **Action**: Cancel request with that peer +- **Recovery**: Retry with different peer if available +- **User Notification**: If all retry attempts exhausted, `requestBlock` returns timeout error + +### Protocol Violations + +**Oversized Messages:** + +- **Condition**: Message exceeds maximum size limits +- **Action**: Close stream immediately +- **Peer Management**: Mark peer as non-compliant +- **No Response**: Do not send error message (message may be malicious) + +**Invalid WantList:** + +- **Condition**: WantList exceeds entry limit or contains malformed addresses +- **Action**: Ignore malformed entries, process valid ones +- **Response**: Continue processing stream +- **Logging**: Log validation errors for debugging + +**Payment Failures:** + +- **Condition**: State channel update invalid or payment insufficient +- **Action**: Do not deliver blocks requiring payment +- **Response**: Send BlockPresence with price indicating payment needed +- **Stream**: Keep stream open for payment retry + +### Recovery Strategies + +#### Retry Responsibility Model + +The protocol defines a clear separation between system-level and caller-level +retry responsibilities: + +**System-Level Retry (Automatic):** + +The Block Exchange module automatically retries in these scenarios: + +- **Peer failure**: If a peer disconnects or times out, the system + transparently tries alternative peers from the discovery set +- **Transient errors**: Network glitches, temporary unavailability +- **Peer rotation**: Automatic failover to next available peer + +The caller's `requestBlock` call remains pending during system-level retries. +This is transparent to the caller. + +**Caller-Level Retry (Manual):** + +The caller is responsible for retry decisions when: + +- **All peers exhausted**: No more peers available from discovery +- **Permanent failures**: Block doesn't exist in the network +- **Timeout exceeded**: Request timeout (300s) expired +- **Verification failures**: All peers provided invalid data + +In these cases, `requestBlock` returns an error and the caller decides +whether to retry, perhaps after waiting or refreshing the peer list +via discovery. + +**Retry Flow:** + +```text +requestBlock(address) + │ + ├─► System tries Peer A ──► Fails + │ │ + │ └─► System tries Peer B ──► Fails (automatic, transparent) + │ │ + │ └─► System tries Peer C ──► Success ──► Return block + │ + └─► All peers failed ──► Return error to caller + │ + └─► Caller decides: retry? wait? abort? +``` + +**Peer Rotation:** + +When a peer fails to deliver blocks: + +1. Mark peer as temporarily unavailable for this block +2. Query discovery service for alternative peers +3. Send WantList to new peers +4. Implement exponential backoff before retrying failed peer + +**Graceful Degradation:** + +- If verification fails, request block from alternative peer +- If all peers fail, propagate error to caller +- Clean up resources (memory, pending requests) on unrecoverable failures + +**Error Propagation:** + +- Service interface functions (`requestBlock`, `cancelRequest`) return errors + to callers only after system-level retries are exhausted +- Internal errors logged for debugging +- Network errors trigger automatic peer rotation before surfacing to caller +- Verification errors result in block rejection and peer reputation impact + ## Security Considerations ### Block Verification From dabc31786b4a4ca704ebcd1105239faff7ac2b47 Mon Sep 17 00:00:00 2001 From: Prem Chaitanya Prathi Date: Mon, 15 Dec 2025 13:26:43 +0530 Subject: [PATCH 6/6] fixing format errors in mix rfc (#229) image --- vac/raw/mix.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vac/raw/mix.md b/vac/raw/mix.md index 2052d65..4319a74 100644 --- a/vac/raw/mix.md +++ b/vac/raw/mix.md @@ -762,8 +762,8 @@ The construction MUST proceed as follows: $` \begin{array}{l} Φ_i = \mathrm{AES\text{-}CTR}'_i\bigl(Φ_{\mathrm{aes\_key}_{i-1}}, - Φ_{\mathrm{iv}_{i-1}}, Φ_{i-1} \mid 0_{(t+1)κ} \bigr),\; \; \; - \text{where notation } 0_x \text{ defines the string of } 0 \text{ bits of length } x\text{.} + Φ_{\mathrm{iv}_{i-1}}, Φ_{i-1} \mid 0_{(t+1)κ} \bigr), \\ + \text{where } 0_x \text{ defines the string of } 0 \text{ bits of length } x\text{.} \end{array} `$ @@ -794,7 +794,7 @@ The construction MUST proceed as follows: - Set the per hop two-byte encoded delay $\mathrm{delay}_i$ as defined in [Section 8.4](#84-address-and-delay-encoding): - If final hop (_i.e.,_ $i = L - 1$), encode two byte zero padding. - - For all other hop $i,\ i < L - 1$, select the mean forwarding delay for the delay strategy configured by the application, and encode it as a two-byte value. The delay strategy is pluggable, as defined in [Section 6.2](#62-delay-strategy). + - For all other hop $i$, $i < L - 1$, select the mean forwarding delay for the delay strategy configured by the application, and encode it as a two-byte value. The delay strategy is pluggable, as defined in [Section 6.2](#62-delay-strategy). - Using the derived keys and encoded forwarding delay, compute the nested encrypted routing information $β_i$: