mirror of
https://github.com/vacp2p/rfc-index.git
synced 2026-01-06 22:34:02 -05:00
RFC Refactor: Sphinx Packet Format (#173)
This commit is contained in:
531
vac/raw/mix.md
531
vac/raw/mix.md
@@ -120,6 +120,18 @@ 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.
|
||||
|
||||
- **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.
|
||||
|
||||
## 3. Motivation and Background
|
||||
|
||||
libp2p enables modular peer-to-peer applications, but it lacks built-in support
|
||||
@@ -194,7 +206,7 @@ describe the core components of a mix network.
|
||||
|
||||
The Mix Protocol relies on two core design elements to achieve sender
|
||||
unlinkability and metadata
|
||||
protection: a mixing strategy and a a cryptographically secure mix packet
|
||||
protection: a mixing strategy and a cryptographically secure mix packet
|
||||
format.
|
||||
|
||||
### 4.1 Mixing Strategy
|
||||
@@ -297,7 +309,7 @@ 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
|
||||
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
|
||||
@@ -458,8 +470,8 @@ 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 a
|
||||
stream over multiple
|
||||
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.
|
||||
@@ -512,9 +524,9 @@ 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
|
||||
—an extension
|
||||
over [Discv5](https://github.com/ethereum/devp2p/blob/master/discv5/discv5.md)
|
||||
— demonstrates
|
||||
—demonstrates
|
||||
an approximate solution. It combines topic-based capability advertisement with
|
||||
periodic
|
||||
peer sampling. A similar strategy could potentially be adapted for the Mix
|
||||
@@ -618,7 +630,7 @@ _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
|
||||
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
|
||||
@@ -627,7 +639,7 @@ 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
|
||||
such traffic—such as timing and frequency—is pluggable and not
|
||||
specified
|
||||
in this document.
|
||||
|
||||
@@ -667,9 +679,9 @@ 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,
|
||||
sophisticated economic models—such as stake-based participation,
|
||||
credentialed relay networks,
|
||||
or zero-knowledge proof-of-contribution systems — MAY be layered on top of
|
||||
or zero-knowledge proof-of-contribution systems—MAY be layered on top of
|
||||
the protocol or
|
||||
enforced via external coordination.
|
||||
|
||||
@@ -779,6 +791,11 @@ 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.
|
||||
|
||||
## 8. Sphinx Packet Format
|
||||
|
||||
The Mix Protocol uses the Sphinx packet format to enable unlinkable, multi-hop
|
||||
@@ -789,8 +806,10 @@ 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 delay value, without learning the complete path or the
|
||||
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
|
||||
@@ -820,12 +839,10 @@ 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
|
||||
@@ -833,8 +850,9 @@ 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.
|
||||
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.
|
||||
@@ -843,12 +861,12 @@ 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.
|
||||
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,
|
||||
@@ -866,20 +884,29 @@ This section defines the cryptographic primitives used in Sphinx packet
|
||||
construction and processing.
|
||||
|
||||
- **Security Parameter**: All cryptographic operations target a minimum of
|
||||
$\kappa = 128$ bits 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$.
|
||||
|
||||
- **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.
|
||||
- **Construction**: SHA-256 hash with output truncated to 128 bits.
|
||||
- **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.
|
||||
@@ -889,9 +916,457 @@ are fixed strings and MUST be agreed upon across implementations.
|
||||
- **Keys and IVs**: Each derived from the session key for the hop using the KDF.
|
||||
|
||||
- **Message Authentication Code (MAC)**:
|
||||
- **Construction**: HMAC-SHA-256 with output truncated to 128 bits.
|
||||
- **Construction**: HMAC-SHA-256 with output truncated to $128$ bits.
|
||||
- **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.
|
||||
|
||||
### 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:
|
||||
|
||||
```text
|
||||
+--------+----------+--------+----------+
|
||||
| α | β | γ | δ |
|
||||
| 32 B | variable | 16 B | variable |
|
||||
+--------+----------+--------+----------+
|
||||
```
|
||||
|
||||
#### 8.3.1 Header Field Sizes
|
||||
|
||||
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.
|
||||
|
||||
- **$β$ (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.
|
||||
|
||||
- **Per-hop $γ$ size ($κ$)** (defined below): Accounts for the integrity tag
|
||||
included with each hop’s routing information.
|
||||
|
||||
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:
|
||||
|
||||
$`
|
||||
\begin{aligned}
|
||||
|Header| &= α + β + γ \\
|
||||
&= 32 + ((t + 1)r + 1)κ + 16
|
||||
\end{aligned}
|
||||
`$
|
||||
|
||||
Notation: $|x|$ denotes the size (in bytes) of field $x$.
|
||||
|
||||
Using the recommended value of $r = 5$ and $t = 6$, the header size is:
|
||||
|
||||
$`
|
||||
\begin{aligned}
|
||||
|Header| &= 32 + 576 + 16 \\
|
||||
&= 624 \ bytes
|
||||
\end{aligned}
|
||||
`$
|
||||
|
||||
#### 8.3.2 Payload Size
|
||||
|
||||
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:
|
||||
|
||||
$`
|
||||
\begin{aligned}
|
||||
|δ| &= TotalPacketSize - HeaderSize
|
||||
\end{aligned}
|
||||
`$
|
||||
|
||||
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),
|
||||
- Allow inclusion of additional data such as SURBs without requiring fragmentation,
|
||||
- Maintain reasonable per-hop processing and bandwidth overhead.
|
||||
|
||||
This recommended total packet size of \$4608\$ bytes yields:
|
||||
|
||||
$`
|
||||
\begin{aligned}
|
||||
Payload &= 4608 - 624 \\
|
||||
&= 3984\ bytes
|
||||
\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].
|
||||
|
||||
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.
|
||||
|
||||
#### 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.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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/<ipv4>/tcp/<port>/p2p/<relayPeerID>/p2p-circuit/p2p/<relayedPeerID>
|
||||
`
|
||||
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.
|
||||
|
||||
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) in
|
||||
milliseconds, using big endian network byte order.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
#### 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:
|
||||
|
||||
- **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).
|
||||
|
||||
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.
|
||||
- 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.
|
||||
- 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}$.
|
||||
|
||||
3. **Wrap Plaintext Payload In Sphinx Packet**
|
||||
|
||||
a. **Compute Ephemeral Secrets**
|
||||
|
||||
- Choose a random private exponent $x \in_R \mathbb{Z}_q^*$.
|
||||
- Initialize:
|
||||
$`
|
||||
\begin{aligned}
|
||||
α_0 &= g^x \\
|
||||
s_0 &= y_0^x \\
|
||||
b_0 &= H(α_0\ |\ s_0)
|
||||
\end{aligned}
|
||||
`$
|
||||
- For each hop $i$ (from $1$ to $L-1$), compute:
|
||||
$`
|
||||
\begin{aligned}
|
||||
α_i &= α_{i-1}^{b_{i-1}} \\
|
||||
s_i &= y_{i}^{x\prod_{\text{j=0}}^{\text{i-1}} b_{j}} \\
|
||||
b_i &= H(α_i\ |\ s_i)
|
||||
\end{aligned}
|
||||
`$
|
||||
|
||||
Note that the length of $α_i$ is $32$ bytes as defined in
|
||||
[Section 8.3](#83-packet-component-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.
|
||||
|
||||
To compute the sequence of filler strings, perform the following steps:
|
||||
|
||||
- Initialize $Φ_0 = \epsilon$ (empty string).
|
||||
- For each $i$ (from $1$ to $L-1$):
|
||||
|
||||
- Derive per-hop AES key and IV:
|
||||
|
||||
$`
|
||||
\begin{array}{l}
|
||||
Φ_{\mathrm{aes\_key}_{i-1}} =
|
||||
\mathrm{KDF}(\text{"aes\_key"} \mid s_{i-1})\\
|
||||
Φ_{\mathrm{iv}_{i-1}} =
|
||||
\mathrm{KDF}(\text{"iv"} \mid s_{i-1})
|
||||
\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)\kappa$ :
|
||||
|
||||
$`
|
||||
\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),
|
||||
\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$.
|
||||
|
||||
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.
|
||||
|
||||
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:
|
||||
|
||||
- Derive per-hop AES key, MAC key, and IV:
|
||||
|
||||
$`
|
||||
\begin{array}{l}
|
||||
β_{\mathrm{aes\_key}_i} =
|
||||
\mathrm{KDF}(\text{"aes\_key"} \mid s_i)\\
|
||||
\mathrm{mac\_key}_i =
|
||||
\mathrm{KDF}(\text{"mac\_key"} \mid s_{i})\\
|
||||
β_{\mathrm{iv}_i} =
|
||||
\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):
|
||||
- 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).
|
||||
|
||||
- Using the derived keys and encoded forwarding delay, compute the nested
|
||||
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}
|
||||
\bigr) \bigm| Φ_{L-1}
|
||||
\end{array}
|
||||
`$
|
||||
|
||||
- Otherwise (_i.e.,_ intermediary node):
|
||||
|
||||
$`
|
||||
\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)
|
||||
\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).
|
||||
|
||||
- Compute the message authentication code $γ_i$:
|
||||
|
||||
$`
|
||||
\begin{array}{l}
|
||||
γ_i = \mathrm{HMAC\text{-}SHA\text{-}256}\bigl(\mathrm{mac\_key}_i,
|
||||
β_i \bigr)
|
||||
\end{array}
|
||||
`$
|
||||
|
||||
Note that the length of $\gamma_i$ is $\kappa$ as defined in
|
||||
[Section 8.3](#83-packet-component-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:
|
||||
|
||||
- Derive per-hop AES key and IV:
|
||||
|
||||
$`
|
||||
\begin{array}{l}
|
||||
δ_{\mathrm{aes\_key}_i} =
|
||||
\mathrm{KDF}(\text{"δ\_aes\_key"} \mid s_i)\\
|
||||
δ_{\mathrm{iv}_i} =
|
||||
\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):
|
||||
|
||||
$`
|
||||
\begin{array}{l}
|
||||
δ_i = \mathrm{AES\text{-}CTR}\bigl(δ_{\mathrm{aes\_key}_i},
|
||||
δ_{\mathrm{iv}_i}, 0_{\kappa} \mid m
|
||||
\bigr)
|
||||
\end{array}
|
||||
`$
|
||||
|
||||
- Otherwise (_i.e.,_ intermediary node):
|
||||
|
||||
$`
|
||||
\begin{array}{l}
|
||||
δ_i = \mathrm{AES\text{-}CTR}\bigl(δ_{\mathrm{aes\_key}_i},
|
||||
δ_{\mathrm{iv}_i}, δ_{i+1} \bigr)
|
||||
\end{array}
|
||||
`$
|
||||
|
||||
Reference in New Issue
Block a user