mirror of
https://github.com/vacp2p/rfc-index.git
synced 2026-01-08 23:28:15 -05:00
2nd resolve vac/raw/mix.md conflict
This commit is contained in:
463
vac/raw/mix.md
463
vac/raw/mix.md
@@ -315,14 +315,6 @@ between the origin protocol and the Mix Protocol instances. This enables
|
||||
selective anonymous routing
|
||||
without modifying protocol semantics or internal behavior.
|
||||
|
||||
<<<<<<< HEAD
|
||||
4. **Delta ($δ$)**: The encrypted payload, which can be of variable size.
|
||||
- According to the [MixMatch](https://petsymposium.org/popets/2024/popets-2024-0050.pdf)
|
||||
paper, the Nym network uses Sphinx packets of a fixed
|
||||
size (2413 bytes).
|
||||
- Considering this, the maximum $δ$ size can be chosen as 2413 bytes minus
|
||||
the header length (which will be derived below).
|
||||
=======
|
||||
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
|
||||
@@ -330,7 +322,6 @@ the `mixify` flag,
|
||||
the rationale for defining Mix as a protocol rather than a transport, and the
|
||||
end-to-end message
|
||||
interaction flow.
|
||||
>>>>>>> main
|
||||
|
||||
### 5.1 Integration with Origin Protocols
|
||||
|
||||
@@ -342,16 +333,10 @@ via the Mix Entry and Exit layers.
|
||||
protocol and forwards them
|
||||
to the local Mix Protocol instance.
|
||||
|
||||
<<<<<<< HEAD
|
||||
The entire Sphinx packet header ($α$, $β$, and $γ$) can fit within a fixed size
|
||||
of $32 + (r(t+1)+1)\kappa + 16 = 384$ bytes, leaving ample room for a large $δ$ of
|
||||
up to $2413 - 384 = 2029$ bytes.
|
||||
=======
|
||||
- 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.
|
||||
>>>>>>> main
|
||||
|
||||
This integration is external to the Mix Protocol and is not handled by mix nodes
|
||||
themselves.
|
||||
@@ -767,453 +752,6 @@ processing and behavior.
|
||||
|
||||
After decrypting one layer of the Sphinx packet, the node MUST inspect the
|
||||
routing information.
|
||||
<<<<<<< HEAD
|
||||
|
||||
```proto
|
||||
message SphinxPacket {
|
||||
bytes alpha = 1; // 32 bytes
|
||||
bytes beta = 2; // 304 - 384 bytes
|
||||
bytes gamma = 3; // 16 bytes
|
||||
bytes delta = 4; // variable size, max 2029 bytes
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Handler Function
|
||||
|
||||
The [handler function](https://docs.libp2p.io/concepts/fundamentals/protocols/#handler-functions)
|
||||
is responsible for processing connections and messages for
|
||||
the Mix protocol. It operates according to the mix node roles (_i.e.,_ sender,
|
||||
intermediary mix node, or exit node) defined in
|
||||
[Section 2.1](#21-mix-nodes-roles). This function is crucial for implementing
|
||||
the core functionality of the mixnet protocol within the libp2p framework.
|
||||
|
||||
When a node receives a new stream for the `"/mix/1.0.0"` protocol, the handler
|
||||
function is invoked. It performs different operations based on the node's role
|
||||
in the current message path:
|
||||
|
||||
- **Role Determination**
|
||||
|
||||
The handler first determines the node's role for the incoming message. This
|
||||
is typically done by examining the packet structure and the node's position
|
||||
in the network.
|
||||
|
||||
- **Packet Processing**
|
||||
|
||||
Depending on the role, the handler processes the Sphinx packet differently:
|
||||
|
||||
- For senders, it creates and sends new Sphinx packets.
|
||||
- For intermediary nodes, it processes and forwards existing packets.
|
||||
- For exit nodes, it decrypts the final layer and disseminates the original message.
|
||||
|
||||
- **Error Handling**
|
||||
|
||||
It manages any errors that occur during packet processing, such as invalid
|
||||
MACs or decryption failures.
|
||||
|
||||
- **Logging and Metrics**
|
||||
|
||||
The handler is also be responsible for logging important events and
|
||||
collecting metrics for network analysis and debugging.
|
||||
|
||||
The specific implementation of the handler function for each role (_i.e.,_
|
||||
sender, intermediary, and exit node) is detailed in the following subsections.
|
||||
|
||||
#### 5.1 Sender
|
||||
|
||||
1. **Convert the libp2p Message to Bytes**
|
||||
|
||||
Serialize the libp2p message to bytes and store the result in
|
||||
`libp2p_message`. This can be done using Protocol Buffers or another
|
||||
serialization method.
|
||||
|
||||
2. **Apply Spam Protection**
|
||||
|
||||
Apply the chosen spam protection mechanism to the `libp2p_message`.
|
||||
This could be Proof of Work (PoW), Verifiable Delay Function (VDF),
|
||||
Rate Limiting Nullifier (RLN), or other suitable approaches.
|
||||
|
||||
Refer to [Appendix A](#appendix-a-example-spam-protection-using-proof-of-work)
|
||||
for details on the current implementation using PoW.
|
||||
|
||||
3. **Prepare the Message**
|
||||
|
||||
Prepare the `message` by combining the `libp2p_message` with any necessary data
|
||||
from the spam protection mechanism. The exact format of `message` will depend
|
||||
on the chosen spam protection method.
|
||||
|
||||
Note: The spam protection mechanism is designed as a pluggable interface,
|
||||
allowing for different methods to be implemented based on network requirements.
|
||||
This flexibility extends to other components such as peer discovery and incentivization,
|
||||
which are not specified in detail to allow for future optimizations and adaptations.
|
||||
|
||||
4. **Perform Path Selection** (refer [Section 2.4](#24-node-discovery))
|
||||
|
||||
- Let the Ed25519 public keys of the mix nodes in the path be
|
||||
$y_0,\ y_1,\ \ldots,\ y_{L-1}$.
|
||||
|
||||
5. **Wrap Final Message in Sphinx Packet**
|
||||
Perform the following steps to wrap `message` in a Sphinx packet:
|
||||
|
||||
a. **Compute** **Alphas ($α_i$**, **$i=0$** to **$L-1$)**
|
||||
|
||||
- Select a random exponent $x$ from $\mathbb{Z}_q^*$.
|
||||
- Compute initial alpha $α_0$, shared secret $s_0$, and blinding factor $b_0$:
|
||||
- $α_0 = g^x$ using Curve25519 scalar multiplication.
|
||||
- $s_0 = y_0^x$, where $y_0$ is the public key of the first hop.
|
||||
- $b_0 = H(α_0\ |\ s_0)$, where $H$ is the SHA-256 hash function (refer
|
||||
_[Section 3](#3-cryptographic-primitives-and-security-parameter)_ for details).
|
||||
- For each node $i$ (from $1$ to $L-1$):
|
||||
- $α_i = α_{i-1}^{b_{i-1}}$ using Curve25519 scalar multiplication.
|
||||
- $s_i = y_{i}^{x\prod_{\text{j=0}}^{\text{i-1}} b_{j}}$, where $y_{i}$ is
|
||||
the public key of the i-th hop.
|
||||
- $b_i = H(α_i\ |\ s_i)$, where $H$ is the SHA-256 hash function.
|
||||
|
||||
Note that $\alpha_i$ and $s_i$ are group elements, each 32 bytes long.
|
||||
|
||||
b. **Compute** **Filler Strings ($\phi_i$**, **$i=0$** to **$L-1$)**
|
||||
|
||||
- Initialize $\phi_0$ as an empty string.
|
||||
- For each $i$ (from $1$ to $L-1$):
|
||||
|
||||
- Derive the AES key and IV:
|
||||
|
||||
$`\text{φ\_aes\_key}_{i-1} = KDF(\text{"aes\_key"}\ |\ s_{i-1})`$
|
||||
|
||||
$`\text{φ\_iv}_{i-1} = H(\text{"iv"}\ |\ s_{i-1})`$ (truncated to 128 bits)
|
||||
|
||||
- Compute the filler string $\phi_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$ :
|
||||
|
||||
$`\phi_i = \text{AES-CTR}^\prime_i(\text{φ\_aes\_key}_{i-1},\ \text{φ\_iv}_{i-1},
|
||||
\ \phi_{i-1}\ |\ 0_{(t+1)\kappa})`$,
|
||||
where $0_{(t+1)\kappa}$ is the string of $0$ bits of length $(t+1)\kappa$.
|
||||
|
||||
Note that the length of $\phi_i$ is $(t+1)i\kappa$.
|
||||
|
||||
c. **Compute** **Betas and Gammas ($\beta_i$**, $\gamma_i$, **$i=0$** to **$L-1$)**
|
||||
|
||||
For each $i$ (from $L-1$ to $0$):
|
||||
|
||||
- Derive the AES key, MAC key, and IV:
|
||||
|
||||
$`\text{β\_aes\_key}_{i} = KDF(\text{"aes\_key"}\ |\ s_{i})`$
|
||||
|
||||
$`\text{mac\_key}_{i} = KDF(\text{"mac\_key"}\ |\ s_{i})`$
|
||||
|
||||
$`\text{β\_iv}_{i} = H(\text{"iv"}\ |\ s_{i})`$ (truncated to 128 bits)
|
||||
|
||||
- Generate random $`\text{delay\_i}`$, a 16-bit unsigned integer (0-65535 milliseconds).
|
||||
|
||||
Note that top-level applications can use other probability distributions,
|
||||
such as an exponential distribution, where shorter delays are more likely
|
||||
than longer delays. This can mimic real-world traffic patterns and provide
|
||||
robust anonymity against traffic analysis. The trade-off lies in balancing
|
||||
the need for flexible delay handling with the risk of exposing
|
||||
application-specific traffic patterns.
|
||||
|
||||
- If $i = L-1$ (_i.e.,_ exit node):
|
||||
|
||||
$`\beta_i = \text{AES-CTR}(\text{β\_aes\_key}_{i},\ \text{β\_iv}_{i},\ 0_{((t+1)
|
||||
(r-L)+t+2)\kappa})\ |\ \phi_{L-1}`$
|
||||
|
||||
- Otherwise (_i.e.,_ intermediary node):
|
||||
|
||||
$`\beta_i = \text{AES-CTR}(\text{β\_aes\_key}_{i},\ \text{β\_iv}_{i},\ \text
|
||||
{addr}_{i+1} \ |\ \text{delay}_{i+1}\ | \ \gamma_{i+1}\ |\ {\beta_{i+1}}_
|
||||
{[0\ldots(r(t+1)-t)\kappa−1]})`$
|
||||
|
||||
Note that the length of $\beta_i$ is $(r(t+1)+1)\kappa$, $0 \leq i \leq L-1$,
|
||||
where $t$ is the combined length of next hop address and delay.
|
||||
|
||||
- $`\gamma_i = \text{HMAC-SHA-256}(\text{mac\_key}_i,\ β_i)`$\
|
||||
Note that the length of $\gamma_i$ is $\kappa$.
|
||||
|
||||
d. **Compute** **Deltas (**$\delta_i$, **$i=0$** to **$L-1$)**
|
||||
|
||||
For each $i$ (from $L-1$ to $0$):
|
||||
|
||||
- Derive the AES key and IV:
|
||||
|
||||
$`\text{δ\_aes\_key}_{i} = KDF(\text{"δ\_aes\_key"}\ |\ s_{i})`$
|
||||
|
||||
$`\text{δ\_iv}_{i} = H(\text{"δ\_iv"}\ |\ s_{i})`$ (truncated to 128 bits)
|
||||
|
||||
- If $i = L-1$ (_i.e.,_ exit node):
|
||||
|
||||
$`\delta_i = \text{AES-CTR}(\text{δ\_aes\_key}_{i},\ \text{δ\_iv}_{i},
|
||||
\ 0_{\kappa}\ |\ m)`$, where $m$ is the `message`.
|
||||
|
||||
- Otherwise (_i.e.,_ intermediary node):
|
||||
|
||||
$`\delta_i = \text{AES-CTR}(\text{δ\_aes\_key}_{i},\ \text{δ\_iv}_{i},\ \delta_{i+1})`$
|
||||
|
||||
Note that the length of $\delta$ is $|m| + \kappa$.
|
||||
|
||||
Given that the derived size of $\delta$ is $2029$ bytes, this allows
|
||||
`message` to be of length $2029-16 = 2013$ bytes. This means smaller
|
||||
messages may need to be padded up to $2013$ bytes (e.g., using PKCS#7
|
||||
padding).
|
||||
|
||||
e. **Construct Final Sphinx Packet**
|
||||
|
||||
- Initialize header
|
||||
|
||||
```pseudocode
|
||||
alpha = alpha_0 // 32 bytes
|
||||
beta = beta_0 // $(r(t+1)+1)\kappa$ bytes
|
||||
gamma = gamma_0 // 16 bytes
|
||||
```
|
||||
|
||||
As discussed earlier, for a maximum path length of $r = 5$, and combined
|
||||
length of address and delay $t = 3\kappa = 48$ bytes, the header size is
|
||||
just $384$ bytes.
|
||||
- Initialize payload
|
||||
|
||||
`delta = delta_0 // variable size, max 2029 bytes`
|
||||
|
||||
For a fixed Sphinx packet size of $2413$ bytes and given the header length
|
||||
of $384$ bytes, `delta` size is $2029$ bytes.
|
||||
|
||||
6. **Serialize the Sphinx Packet** using Protocol Buffers.
|
||||
|
||||
7. **Send the Serialized Packet** to the first mix node using the
|
||||
`"/mix/1.0.0"` protocol.
|
||||
|
||||
#### 5.2 Intermediary Mix Node
|
||||
|
||||
Let $`x_i \in \mathbb{Z}_q^*`$ be the intermediary node’s private key
|
||||
corresponding to the public key $y_i \in G^*$. It performs the following steps
|
||||
to relay a message:
|
||||
|
||||
1. **Receive and Deserialize** the Sphinx packet using Protocol Buffers.
|
||||
2. **Compute Shared Secret $s = \alpha^{x_{i}}$**.
|
||||
|
||||
3. **Check If Previously Seen**
|
||||
|
||||
a. Compute tag $H(s)$, where $H$ is the SHA-256 hash function.
|
||||
|
||||
b. If tag is in the previously seen list of tags, discard the message.
|
||||
|
||||
c. This list can be reset whenever the node rotates its private key
|
||||
|
||||
4. **Compute MAC**
|
||||
|
||||
a. Derive MAC key
|
||||
|
||||
$`\text{mac\_key} = KDF(\text{"mac\_key"}\ |\ s)`$
|
||||
|
||||
b. Check if $`\gamma = \text{HMAC-SHA-256}(\text{mac\_key},\ β)`$ . If not,
|
||||
discard the message.
|
||||
|
||||
c. Otherwise, store tag $H(s)$ in the list of seen message tags.
|
||||
|
||||
5. **Decrypt One Layer**
|
||||
|
||||
a. Derive the AES key, MAC key, and IV:
|
||||
|
||||
$`\text{β\_aes\_key} = KDF(\text{"aes\_key"}\ |\ s)`$
|
||||
|
||||
$`\text{β\_iv} = H(\text{"iv"}\ |\ s)`$ (truncated to 128 bits)
|
||||
|
||||
b. Compute
|
||||
$`B = \text{AES-CTR}(\text{β\_aes\_key},\ \text{β\_iv},\ \beta\ |\ 0_{(t+1)k})`$.
|
||||
|
||||
c. Uniquely parse prefix of $B$
|
||||
|
||||
If $B$ has a prefix of **$0_{((t+1)(r-L)+t+2)\kappa}$,** the current node is the
|
||||
exit node (refer exit node operations below).
|
||||
|
||||
Otherwise, it is an intermediary node and it performs the followings steps
|
||||
to relay the message.
|
||||
|
||||
d. **Extract Routing Information**
|
||||
|
||||
$`\text{next\_hop} = B_{[0\ldots(t\kappa-17)]}`$ (first $t\kappa-2$ bytes).
|
||||
|
||||
e. **Extract Delay**
|
||||
|
||||
$`\text{delay} = B_{[(t\kappa-16)\ldots(t\kappa-1)]}`$ (following $2$ bytes).
|
||||
|
||||
f. **Extract Gamma**
|
||||
|
||||
$`{\gamma}' = B_{[t\kappa\ldots(t\kappa+\kappa-1)]}`$ (following $\kappa$ bytes).
|
||||
|
||||
g. **Extract Beta**
|
||||
|
||||
$`\beta' = B_{[(t\kappa+\kappa)\ldots(r(t+1)+t+2)\kappa-1]}`$ (following
|
||||
$((t+1)r + 1)\kappa$ bytes).
|
||||
|
||||
h. **Compute Alpha**
|
||||
|
||||
- Compute blinding factor $b = H(α\ |\ s)$, where $H$ is the SHA-256 hash
|
||||
function.
|
||||
- Compute $α^′ = α^b$.
|
||||
|
||||
i. **Compute Delta**
|
||||
|
||||
- Derive the AES key and IV:
|
||||
$`\text{δ\_aes\_key} = KDF(\text{"δ\_aes\_key"}\ |\ s)`$
|
||||
$`\text{δ\_iv} = H(\text{"δ\_iv"}\ |\ s)$` (truncated to 128 bits)
|
||||
- Compute $`\delta' = \text{AES-CTR}(\text{δ\_aes\_key},\ \text{δ\_iv},\ \delta)`$
|
||||
|
||||
6. **Construct Final Sphinx Packet**
|
||||
|
||||
a. Initialize header
|
||||
|
||||
```pseudocode
|
||||
alpha = alpha' // 32 bytes
|
||||
beta = beta' // $((t+1)r + 1)\kappa$ bytes
|
||||
gamma = gamma' // 16 bytes
|
||||
```
|
||||
|
||||
b. Initialize payload
|
||||
|
||||
`delta = delta' // variable size, max 2029 bytes`
|
||||
|
||||
7. **Serialize the Sphinx Packet** using Protocol Buffers.
|
||||
8. **Introduce A Delay** of $`\text{delay}`$ milliseconds.
|
||||
9. **Send the Serialized Packet** to $`\text{next\_hop}`$ using the
|
||||
`"/mix/1.0.0"` protocol.
|
||||
|
||||
#### 5.3 Exit Node
|
||||
|
||||
1. **Perform _Steps i. to v. b._ Above**, similar to an intermediary node. If
|
||||
$B$ has a prefix of $0_{((t+1)(r-L)+t+2)\kappa}$ (in _step 5. c._ above), the
|
||||
current node is the exit node. It performs the following steps to
|
||||
disseminate the message via the respective libp2p protocol.
|
||||
|
||||
2. **Compute Delta**
|
||||
|
||||
- Derive the AES key and IV:
|
||||
|
||||
$`\text{δ\_aes\_key} = KDF(\text{"δ\_aes\_key"}\ |\ s)`$
|
||||
|
||||
$`\text{δ\_iv} = H(\text{"δ\_iv"}\ |\ s)`$ (truncated to 128 bits)
|
||||
|
||||
- Compute $`\delta' = \text{AES-CTR}(\text{δ\_aes\_key},\ \text{δ\_iv},\ \delta)`$.
|
||||
|
||||
3. **Extract Message**
|
||||
|
||||
$m = \delta'_{[\kappa\ldots]}$ (remove first $\kappa$ bytes).
|
||||
|
||||
4. **Remove Any Padding** from $m$ to obtain the `message` including any
|
||||
necessary spam protection data.
|
||||
|
||||
5. **Verify Spam Protection**
|
||||
|
||||
Verify the spam protection mechanism applied to the `message`.
|
||||
If the verification fails, discard the `message`.
|
||||
Refer to [Appendix A](#appendix-a-example-spam-protection-using-proof-of-work)
|
||||
for details on the current implementation using PoW.
|
||||
|
||||
6. **Deserialize the extracted message** using the respective libp2p protocol's
|
||||
definition.
|
||||
|
||||
7. **Disseminate the message** via the respective libp2p protocol (_e.g.,_
|
||||
GossipSub).
|
||||
|
||||
## Copyright
|
||||
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
||||
|
||||
## References
|
||||
|
||||
### Normative
|
||||
|
||||
[Handler function](https://docs.libp2p.io/concepts/fundamentals/protocols/#handler-functions)
|
||||
[libp2p](https://libp2p.io)\
|
||||
[Sphinx](https://cypherpunks.ca/~iang/pubs/Sphinx_Oakland09.pdf)
|
||||
|
||||
### Informative
|
||||
|
||||
[PoW](https://bitcoin.org/bitcoin.pdf)\
|
||||
[Sphinx packet size](https://petsymposium.org/popets/2024/popets-2024-0050.pdf)
|
||||
|
||||
## Appendix A. Example Spam Protection using Proof of Work
|
||||
|
||||
The current implementation uses a Proof of Work mechanism for spam protection.
|
||||
This section details the specific steps for attaching and verifying the PoW.
|
||||
|
||||
### Structure
|
||||
|
||||
The sender appends the PoW to the serialized libp2p message, `libp2p_message`,
|
||||
in a structured format, making it easy to parse and verify by the exit node.
|
||||
The sender includes the PoW as follows:
|
||||
|
||||
`message = <libp2p_message_bytes | timestamp | nonce>`
|
||||
|
||||
where:
|
||||
|
||||
`<libp2p_message_bytes>`: Serialized libp2p message (variable length).
|
||||
|
||||
`<timestamp>`: The current Unix timestamp in seconds (4 bytes).
|
||||
|
||||
`<nonce>`: The nonce that satisfies the PoW difficulty criterion (4 bytes).
|
||||
|
||||
**Nonce Size:** The nonce size should be large enough to ensure a sufficiently large
|
||||
search space. It should be chosen so that the range of possible nonce values
|
||||
allows for the difficulty target to be met. However, larger nonce sizes can increase
|
||||
the time and computational effort required to find a valid nonce. We use
|
||||
a 4-byte nonce to ensure sufficiently large search space with reasonable
|
||||
computational effort.
|
||||
|
||||
**Difficulty Level:** The difficulty level is usually expressed as the number of
|
||||
leading zeros required in the hash output. It is chosen such that the
|
||||
computational effort required is significant but not prohibitive.
|
||||
We recommend a reasonable difficulty level that requires around
|
||||
16-18 leading zeros in the SHA-256 hash. This would roughly take
|
||||
0.65 to 2.62 seconds to compute in a low-grade CPU,
|
||||
capable of computing 100,000 hashes per second.
|
||||
|
||||
### Calculate Proof of Work (PoW)
|
||||
|
||||
The sender performs the following steps to compute the PoW challenge and response:
|
||||
|
||||
i. **Create Challenge**
|
||||
|
||||
Retrieves the current Unix timestamp, `timestamp`, in seconds (4 bytes).
|
||||
|
||||
ii. **Find A Valid Nonce**
|
||||
|
||||
- Initializes the `nonce` to a 4-byte value (initially zero).
|
||||
|
||||
- Increments the `nonce` until the SHA-256 hash of
|
||||
`<libp2p_message_bytes | timestamp | nonce>` has at least
|
||||
18 leading zeros.
|
||||
|
||||
- The final value of the `nonce` is considered valid.
|
||||
|
||||
### Attach the PoW to the libp2p Message
|
||||
|
||||
Append the 4-byte `timestamp` and the valid `nonce` to
|
||||
the `libp2p_message_bytes` to form the `message`.
|
||||
|
||||
`message = <libp2p_message_bytes | timestamp | nonce>`
|
||||
|
||||
### Verify PoW
|
||||
|
||||
i. **Extract Timestamp and Nonce**
|
||||
|
||||
Split `message` into 4-byte `nonce` (last 4 bytes), 4-byte `timestamp`
|
||||
(the 4 bytes before the nonce), and the serialized libp2p message
|
||||
to be published, `libp2p_message_bytes` (the remaining bytes).
|
||||
|
||||
ii. **Verify Timestamp**
|
||||
|
||||
- Check the `timestamp` is within the last 5 minutes.
|
||||
|
||||
- If the timestamp is outside the acceptable window, the exit node
|
||||
discards the message.
|
||||
|
||||
iii. **Verify Response**
|
||||
|
||||
- Compute the SHA-256 hash of the `message` and check if the hash
|
||||
meets the difficulty requirement, _i.e._, has at least 18 leading zeros.
|
||||
|
||||
- If the hash is not valid, the exit node discards the message. Otherwise,
|
||||
it follows the steps to publish the message.
|
||||
=======
|
||||
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.
|
||||
@@ -1357,4 +895,3 @@ are fixed strings and MUST be agreed upon across implementations.
|
||||
|
||||
These primitives are used consistently throughout packet construction and
|
||||
decryption, as described in the following sections.
|
||||
>>>>>>> main
|
||||
|
||||
Reference in New Issue
Block a user