aboutsummaryrefslogtreecommitdiff
path: root/spec/hspow-spec
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2024-02-06 11:18:31 -0500
committerNick Mathewson <nickm@torproject.org>2024-02-06 13:00:44 -0500
commitdb80b935f799ab44750ff378267b10a967af38e3 (patch)
tree12be4d952e51f6102fee807c25532025fad91def /spec/hspow-spec
parentad73886e2a38255b5b0b599628f67fe820a5c440 (diff)
downloadtorspec-db80b935f799ab44750ff378267b10a967af38e3.tar.gz
torspec-db80b935f799ab44750ff378267b10a967af38e3.zip
Apply "cell" and "message" consistently
Done by grepping for "cell" and making sure it was accurate in every place where it occurs. In tor-spec, I also searched for "message". Part of #253.
Diffstat (limited to 'spec/hspow-spec')
-rw-r--r--spec/hspow-spec/analysis-discussion.md128
-rw-r--r--spec/hspow-spec/common-protocol.md2
-rw-r--r--spec/hspow-spec/v1-equix.md6
3 files changed, 68 insertions, 68 deletions
diff --git a/spec/hspow-spec/analysis-discussion.md b/spec/hspow-spec/analysis-discussion.md
index e021b85..6585d3f 100644
--- a/spec/hspow-spec/analysis-discussion.md
+++ b/spec/hspow-spec/analysis-discussion.md
@@ -10,7 +10,7 @@ To design a protocol and choose its parameters, we first need to understand a fe
### Overwhelm PoW verification ("top half") {#attack-top-half}
-A basic attack here is the adversary spamming with bogus INTRO cells so that the service does not have computing capacity to even verify the proof-of-work. This adversary tries to overwhelm the procedure in the [`v1` verification algorithm](./v1-equix.md#service-verify) section.
+A basic attack here is the adversary spamming with bogus INTRODUCE messages so that the service does not have computing capacity to even verify the proof-of-work. This adversary tries to overwhelm the procedure in the [`v1` verification algorithm](./v1-equix.md#service-verify) section.
That's why we need the PoW algorithm to have a cheap verification time so that this attack is not possible: we explore this PoW parameter below in the section on [PoW verification](#pow-tuning-verification).
@@ -19,9 +19,9 @@ That's why we need the PoW algorithm to have a cheap verification time so that t
Given the way [the introduction queue](./common-protocol.md#intro-queue) works, a very effective strategy for the attacker is to totally overwhelm the queue processing by sending more high-effort introductions than the onion service can handle at any given tick.
This adversary tries to overwhelm the process of [handling queued introductions](./common-protocol.md#handling-queue).
-To do so, the attacker would have to send at least 20 high-effort introduction cells every 100ms, where high-effort is a PoW which is above the estimated level of ["the motivated user"](./motivation.md#user-profiles).
+To do so, the attacker would have to send at least 20 high-effort INTRODUCE messages every 100ms, where high-effort is a PoW which is above the estimated level of ["the motivated user"](./motivation.md#user-profiles).
-An easier attack for the adversary, is the same strategy but with introduction cells that are all above the comfortable level of ["the standard user"](./motivation.md#user-profiles).
+An easier attack for the adversary, is the same strategy but with INTRODUCE messages that are all above the comfortable level of ["the standard user"](./motivation.md#user-profiles).
This would block out all standard users and only allow motivated users to pass.
### Hybrid overwhelm strategy {#attack-hybrid}
@@ -66,19 +66,19 @@ At the end of this section we will estimate the resources that an attacker needs
### PoW verification {#pow-tuning-verification}
-Verifying a PoW token is the first thing that a service does when it receives an INTRODUCE2 cell. Our current implementation is described by the [`v1` verification algorithm](./v1-equix.md#service-verify) specification.
+Verifying a PoW token is the first thing that a service does when it receives an INTRODUCE2 message. Our current implementation is described by the [`v1` verification algorithm](./v1-equix.md#service-verify) specification.
Verification time is a critical performance parameter. Actual times can be measured by `cargo bench` now, and the verification speeds we achieve are more like 50-120 microseconds. The specific numbers below are dated, but the analysys below is preserved as an illustration of the design space we are optimizing within.
To defend against a [top-half attack](#attack-top-half) it's important that we can quickly perform all the steps in-between receiving an introduction request over the network and adding it to our effort-prioritized queue.
-All time spent verifying PoW adds overhead to the already existing "top half" part of handling an introduction cell.
+All time spent verifying PoW adds overhead to the already existing "top half" part of handling an INTRODUCE message.
Hence we should be careful to add minimal overhead here.
During our [performance measurements on tor](#tor-measurements) we learned that the "top half" takes about 0.26 msecs in average, without doing any sort of PoW verification.
-Using that value we compute the following table, that describes the number of cells we can queue per second (aka times we can perform the "top half" process) for different values of PoW verification time:
+Using that value we compute the following table, that describes the number of requests we can queue per second (aka times we can perform the "top half" process) for different values of PoW verification time:
-| PoW Verification Time | Total "top half" time | Cells Queued per second
+| PoW Verification Time | Total "top half" time | Requests Queued per second
| --------------------- | --------------------- | -----------------------
| 0 msec | 0.26 msec | 3846
| 1 msec | 1.26 msec | 793
@@ -94,9 +94,9 @@ Using that value we compute the following table, that describes the number of ce
Here is how you can read the table above:
-- For a PoW function with a 1ms verification time, an attacker needs to send 793 dummy introduction cells per second to succeed in a [top-half attack](#attack-top-half).
-- For a PoW function with a 2ms verification time, an attacker needs to send 442 dummy introduction cells per second to succeed in a [top-half attack](#attack-top-half).
-- For a PoW function with a 10ms verification time, an attacker needs to send 97 dummy introduction cells per second to succeed in a [top-half attack](#attack-top-half).
+- For a PoW function with a 1ms verification time, an attacker needs to send 793 dummy introduction requests per second to succeed in a [top-half attack](#attack-top-half).
+- For a PoW function with a 2ms verification time, an attacker needs to send 442 dummy requests per second to succeed in a [top-half attack](#attack-top-half).
+- For a PoW function with a 10ms verification time, an attacker needs to send 97 dummy requests per second to succeed in a [top-half attack](#attack-top-half).
Whether an attacker can succeed at that depends on the attacker's resources, but also on the network's capacity.
@@ -104,10 +104,10 @@ Our purpose here is to have the smallest PoW verification overhead possible that
Note that the table above is simply the result of a naive multiplication and does not take into account all the auxiliary overheads that happen every second like the time to invoke the mainloop, the bottom-half processes, or pretty much anything other than the "top-half" processing.
-During our measurements the time to handle INTRODUCE2 cells dominates any other action time:
+During our measurements the time to handle introduction requests dominates any other action time:
There might be events that require a long processing time, but these are pretty infrequent (like uploading a new HS descriptor) and hence over a long time they smooth out.
-Hence extrapolating the total cells queued per second based on a single "top half" time seems like good enough to get some initial intuition.
-That said, the values of "Cells queued per second" from the table above, are likely much smaller than displayed above because of all the auxiliary overheads.
+Hence extrapolating the total introduction requests queued per second based on a single "top half" time seems like good enough to get some initial intuition.
+That said, the values of "Requests queued per second" from the table above, are likely much smaller than displayed above because of all the auxiliary overheads.
### PoW difficulty analysis {#pow-difficulty-analysis}
@@ -165,27 +165,27 @@ With the above table we can create some profiles for starting values of our PoW
#### Analysis based on Tor's performance {#pow-difficulty-tor}
To go deeper here, we can use the [performance measurements on tor](#tor-measurements) to get a more specific intuition on the starting difficulty.
-In particular, we learned that completely handling an introduction cell takes 5.55 msecs in average.
-Using that value, we can compute the following table, that describes the number of introduction cells we can handle per second for different values of PoW verification:
-
-| PoW Verification Time | Total time to handle introduction cell | Cells handled per second
-| --------------------- | --------------------------------------- | ------------------------
-| 0 msec | 5.55 msec | 180.18
-| 1 msec | 6.55 msec | 152.67
-| 2 msec | 7.55 msec | 132.45
-| 3 msec | 8.55 msec | 116.96
-| 4 msec | 9.55 mesc | 104.71
-| 5 msec | 10.55 msec | 94.79
-| 6 msec | 11.55 msec | 86.58
-| 7 msec | 12.55 msec | 79.68
-| 8 msec | 13.55 msec | 73.80
-| 9 msec | 14.55 msec | 68.73
-| 10 msec | 15.55 msec | 64.31
+In particular, we learned that completely handling an introduction request takes 5.55 msecs in average.
+Using that value, we can compute the following table, that describes the number of introduction requests we can handle per second for different values of PoW verification:
+
+| PoW Verification Time | Total time to handle request | Requests handled per second
+| --------------------- | ---------------------------- | ------------------------
+| 0 msec | 5.55 msec | 180.18
+| 1 msec | 6.55 msec | 152.67
+| 2 msec | 7.55 msec | 132.45
+| 3 msec | 8.55 msec | 116.96
+| 4 msec | 9.55 mesc | 104.71
+| 5 msec | 10.55 msec | 94.79
+| 6 msec | 11.55 msec | 86.58
+| 7 msec | 12.55 msec | 79.68
+| 8 msec | 13.55 msec | 73.80
+| 9 msec | 14.55 msec | 68.73
+| 10 msec | 15.55 msec | 64.31
Here is how you can read the table above:
-- For a PoW function with a 1ms verification time, an attacker needs to send 152 high-effort introduction cells per second to succeed in a [bottom-half attack](#attack-bottom-half) attack.
-- For a PoW function with a 10ms verification time, an attacker needs to send 64 high-effort introduction cells per second to succeed in a [bottom-half attack](#attack-bottom-half) attack.
+- For a PoW function with a 1ms verification time, an attacker needs to send 152 high-effort introduction requests per second to succeed in a [bottom-half attack](#attack-bottom-half) attack.
+- For a PoW function with a 10ms verification time, an attacker needs to send 64 high-effort introduction requests per second to succeed in a [bottom-half attack](#attack-bottom-half) attack.
We can use this table to specify a starting difficulty that won't allow our target adversary to succeed in an [bottom-half attack](#attack-bottom-half) attack.
@@ -223,7 +223,7 @@ There are various improvements that can be done in this proposal, and while we a
This is just the beginning in DoS defences for Tor and there are various future designs and schemes that we can investigate. Here is a brief summary of these:
- "More advanced PoW schemes" --
- We could use more advanced memory-hard PoW schemes like MTP-argon2 or Itsuku to make it even harder for adversaries to create successful PoWs. Unfortunately these schemes have much bigger proof sizes, and they won't fit in INTRODUCE1 cells. See #31223 for more details.
+ We could use more advanced memory-hard PoW schemes like MTP-argon2 or Itsuku to make it even harder for adversaries to create successful PoWs. Unfortunately these schemes have much bigger proof sizes, and they won't fit in INTRODUCE1 messages. See #31223 for more details.
- "Third-party anonymous credentials" --
We can use anonymous credentials and a third-party token issuance server on the clearnet to issue tokens based on PoW or CAPTCHA and then use those tokens to get access to the service. See `[REF_CREDS]` for more details.
@@ -267,42 +267,42 @@ The following should be read as if tor is an onion service and thus the end poin
Tor uses libevent for its mainloop.
For network I/O operations, a mainloop event is used to inform tor if it can read on a certain socket, or a connection object in tor.
-From there, this event will empty the connection input buffer (inbuf) by extracting and processing a cell at a time.
-The mainloop is single threaded and thus each cell is handled sequentially.
+From there, this event will empty the connection input buffer (inbuf) by extracting and processing a request at a time.
+The mainloop is single threaded and thus each request is handled sequentially.
-Processing an INTRODUCE2 cell at the onion service means a series of operations (in order):
+Processing an INTRODUCE2 message at the onion service means a series of operations (in order):
-1. Unpack cell from inbuf to local buffer.
+1. Unpack relay cell from inbuf to local buffer.
2. Decrypt cell (AES operations).
-3. Parse cell header and process it depending on its RELAY_COMMAND.
-4. INTRODUCE2 cell handling which means building a rendezvous circuit:
+3. Parse relay message and process it depending on its RELAY_COMMAND.
+4. INTRODUCE2 handling which means building a rendezvous circuit:
- Path selection
- Launch circuit to first hop.
5. Return to mainloop event which essentially means back to step (1).
-Tor will read at most 32 cells out of the inbuf per mainloop round.
+Tor will read at most 32 messages out of the inbuf per mainloop round.
### Requirements for PoW {#tor-pow-queue}
-With this proposal, in order to prioritize cells by the amount of PoW work
-it has done, cells can *not* be processed sequentially as described above.
+With this proposal, in order to prioritize requests by the amount of PoW work
+it has done, requests can *not* be processed sequentially as described above.
-Thus, we need a way to queue a certain number of cells, prioritize them and then process some cell(s) from the top of the queue (that is, the cells that have done the most PoW effort).
+Thus, we need a way to queue a certain number of requests, prioritize them and then process some request(s) from the top of the queue (that is, the requests that have done the most PoW effort).
-We thus require a new cell processing flow that is *not* compatible with current tor design. The elements are:
+We thus require a new request processing flow that is *not* compatible with current tor design. The elements are:
-- Validate PoW and place cells in a priority queue of INTRODUCE2 cells ([the introduction queue](./common-protocol.md#intro-queue)).
-- Defer "bottom half" INTRO2 cell processing for after cells have been queued into the priority queue.
+- Validate PoW and place requests in a priority queue of introduction requests ([the introduction queue](./common-protocol.md#intro-queue)).
+- Defer "bottom half" request processing for after requests have been queued into the priority queue.
### Proposed scheduler {#tor-scheduler}
The intuitive way to address the [queueing requirements](#tor-pow-queue) above would be to do this simple and naive approach:
-1. Mainloop: Empty inbuf INTRODUCE2 cells into priority queue
-2. Process all cells in pqueue
+1. Mainloop: Empty inbuf of introduction requests into priority queue
+2. Process all requests in pqueue
3. Goto (1)
-However, we are worried that handling all those cells before returning to the mainloop opens possibilities of attack by an adversary since the priority queue is not gonna be kept up to date while we process all those cells.
+However, we are worried that handling all those requests before returning to the mainloop opens possibilities of attack by an adversary since the priority queue is not gonna be kept up to date while we process all those requests.
This means that we might spend lots of time dealing with introductions that don't deserve it.
We thus propose to split the INTRODUCE2 handling into two different steps: "top half" and "bottom half" process.
@@ -313,7 +313,7 @@ The top half process is responsible for queuing introductions into the priority
1. Unpack cell from inbuf to local buffer.
2. Decrypt cell (AES operations).
-3. Parse INTRODUCE2 cell header and validate PoW.
+3. Parse INTRODUCE2 message and validate PoW.
4. Return to mainloop event which essentially means step (1).
The top-half basically does all operations from the [main loop](#tor-main-loop) section above, excepting (4).
@@ -322,17 +322,17 @@ An then, the bottom-half process is responsible for handling introductions and d
To achieve this we introduce a new mainloop event to process the priority queue _after_ the top-half event has completed.
This new event would do these operations sequentially:
-1. Pop INTRODUCE2 cell from priority queue.
-2. Parse and process INTRODUCE2 cell.
+1. Pop INTRODUCE2 message from priority queue.
+2. Parse and process INTRODUCE2 message.
3. End event and yield back to mainloop.
#### Scheduling the bottom half process {#sched-bottom-half}
The question now becomes: when should the "bottom half" event get triggered from the mainloop?
-We propose that this event is scheduled in when the network I/O event queues at least 1 cell into the priority queue. Then, as long as it has a cell in the queue, it would re-schedule itself for immediate execution meaning at the next mainloop round, it would execute again.
+We propose that this event is scheduled in when the network I/O event queues at least 1 request into the priority queue. Then, as long as it has a request in the queue, it would re-schedule itself for immediate execution meaning at the next mainloop round, it would execute again.
-The idea is to try to empty the queue as fast as it can in order to provide a fast response time to an introduction request but always leave a chance for more cells to appear between cell processing by yielding back to the mainloop.
+The idea is to try to empty the queue as fast as it can in order to provide a fast response time to an introduction request but always leave a chance for more requests to appear between request processing by yielding back to the mainloop.
With this we are aiming to always have the most up-to-date version of the priority queue when we are completing introductions:
this way we are prioritizing clients that spent a lot of time and effort completing their PoW.
@@ -340,25 +340,25 @@ If the size of the queue drops to 0, it stops scheduling itself in order to not
The network I/O event will re-schedule it in time.
Notice that the proposed solution will make the service handle 1 single introduction request at every main loop event.
-However, when we do performance measurements we might learn that it's preferable to bump the number of cells in the future from 1 to N where N <= 32.
+However, when we do performance measurements we might learn that it's preferable to bump the number of requests in the future from 1 to N where N <= 32.
## Performance measurements
-This section will detail the performance measurements we've done on `tor.git` for handling an INTRODUCE2 cell and then a discussion on how much more CPU time we can add (for PoW validation) before it badly degrades our performance.
+This section will detail the performance measurements we've done on `tor.git` for handling an INTRODUCE2 message and then a discussion on how much more CPU time we can add (for PoW validation) before it badly degrades our performance.
### Tor measurements {#tor-measurements}
-In this section we will derive measurement numbers for the "top half" and "bottom half" parts of handling an introduction cell.
+In this section we will derive measurement numbers for the "top half" and "bottom half" parts of handling an introduction request.
These measurements have been done on tor.git at commit
`80031db32abebaf4d0a91c01db258fcdbd54a471`.
-We've measured several set of actions of the INTRODUCE2 cell handling process on Intel(R) Xeon(R) CPU E5-2650 v4.
+We've measured several set of actions of the INTRODUCE2 message handling process on Intel(R) Xeon(R) CPU E5-2650 v4.
Our service was accessed by an array of clients that sent introduction requests for a period of 60 seconds.
1. Full Mainloop Event
- We start by measuring the full time it takes for a mainloop event to process an inbuf containing INTRODUCE2 cells. The mainloop event processed 2.42 cells per invocation on average during our measurements.
+ We start by measuring the full time it takes for a mainloop event to process an inbuf containing INTRODUCE2 messages. The mainloop event processed 2.42 messages per invocation on average during our measurements.
```text
Total measurements: 3279
@@ -367,7 +367,7 @@ Our service was accessed by an array of clients that sent introduction requests
Mean: 13.43 msec - 3rd Q.: 16.20 msec - Max: 257.95 msec
```
-2. INTRODUCE2 cell processing (bottom-half)
+2. INTRODUCE2 message processing (bottom-half)
We also measured how much time the "bottom half" part of the process takes.
That's the heavy part of processing an introduction request as seen in step (4) of the [main loop](#tor-main-loop) section above:
@@ -382,9 +382,9 @@ Our service was accessed by an array of clients that sent introduction requests
3. Connection data read (top half)
Now that we have the above pieces, we can use them to measure just the "top half" part of the procedure.
- That's when bytes are taken from the connection inbound buffer and parsed into an INTRODUCE2 cell where basic validation is done.
+ That's when bytes are taken from the connection inbound buffer and parsed into an INTRODUCE2 message where basic validation is done.
- There is an average of 2.42 INTRODUCE2 cells per mainloop event and so we divide that by the full mainloop event mean time to get the time for one cell.
+ There is an average of 2.42 INTRODUCE2 messages per mainloop event and so we divide that by the full mainloop event mean time to get the time for one message.
From that we subtract the "bottom half" mean time to get how much the "top half" takes:
```text
@@ -394,10 +394,10 @@ Our service was accessed by an array of clients that sent introduction requests
Mean: 0.26 msec
```
-To summarize, during our measurements the average number of INTRODUCE2 cells a mainloop event processed is ~2.42 cells (7931 cells for 3279 mainloop invocations).
+To summarize, during our measurements the average number of INTRODUCE2 messages a mainloop event processed is ~2.42 messages (7931 messages for 3279 mainloop invocations).
-This means that, taking the mean of mainloop event times, it takes ~5.55msec (13.43/2.42) to completely process an INTRODUCE2 cell.
-Then if we look deeper we see that the "top half" of INTRODUCE2 cell processing takes 0.26 msec in average, whereas the "bottom half" takes around 5.33 msec.
+This means that, taking the mean of mainloop event times, it takes ~5.55msec (13.43/2.42) to completely process an INTRODUCE2 messages.
+Then if we look deeper we see that the "top half" of INTRODUCE2 message processing takes 0.26 msec in average, whereas the "bottom half" takes around 5.33 msec.
The heavyness of the "bottom half" is to be expected since that's where 95% of the total work takes place: in particular the rendezvous path selection and circuit launch.
diff --git a/spec/hspow-spec/common-protocol.md b/spec/hspow-spec/common-protocol.md
index e0910ac..cd98643 100644
--- a/spec/hspow-spec/common-protocol.md
+++ b/spec/hspow-spec/common-protocol.md
@@ -165,7 +165,7 @@ The first challenge in reacting to failure, in our case, is to even accurately a
This proposal introduces a bunch of new ways where a legitimate client can fail to reach the onion service.
Furthermore, there is currently no end-to-end way for the onion service to inform the client that the introduction failed.
-The INTRO_ACK cell is not end-to-end (it's from the introduction point to the client) and hence it does not allow the service to inform the client that the rendezvous is never gonna occur.
+The INTRODUCE_ACK message is not end-to-end (it's from the introduction point to the client) and hence it does not allow the service to inform the client that the rendezvous is never gonna occur.
From the client's perspective there's no way to attribute this failure to the service itself rather than the introduction point, so error accounting is performed separately for each introduction-point.
Prior mechanisms will discard an introduction point that's required too many retries.
diff --git a/spec/hspow-spec/v1-equix.md b/spec/hspow-spec/v1-equix.md
index 77b7f95..025af48 100644
--- a/spec/hspow-spec/v1-equix.md
+++ b/spec/hspow-spec/v1-equix.md
@@ -140,8 +140,8 @@ The specific choice of nonce is entirely up to the client, so parallelization ch
## Client sends its proof in an INTRO1 extension {#intro-ext}
-Now that the client has an answer to the puzzle it's time to encode it into an INTRODUCE1 cell.
-To do so the client adds an extension to the encrypted portion of the INTRODUCE1 cell by using the EXTENSIONS field. The encrypted portion of the INTRODUCE1 cell only gets read by the onion service and is ignored by the introduction point.
+Now that the client has an answer to the puzzle it's time to encode it into an INTRODUCE1 message.
+To do so the client adds an extension to the encrypted portion of the INTRODUCE1 message by using the EXTENSIONS field. The encrypted portion of the INTRODUCE1 message only gets read by the onion service and is ignored by the introduction point.
This extension includes the chosen nonce and effort in full, as well as the actual Equi-X proof.
Clients provide only the first 4 bytes of the seed, enough to disambiguate between multiple recent seeds offered by the service.
@@ -154,7 +154,7 @@ When a service receives an INTRODUCE1 with the `PROOF_OF_WORK` extension, it sho
If it's not enabled, the extension SHOULD BE ignored.
If enabled, even if the suggested effort is currently zero, the service follows the procedure detailed in this section.
-If the service requires the `PROOF_OF_WORK` extension but received an INTRODUCE1 cell without any embedded proof-of-work, the service SHOULD consider this cell as a zero-effort introduction for the purposes of the [priority queue](./common-protocol.md#intro-queue).
+If the service requires the `PROOF_OF_WORK` extension but received an INTRODUCE1 message without any embedded proof-of-work, the service SHOULD consider this message as a zero-effort introduction for the purposes of the [priority queue](./common-protocol.md#intro-queue).
To verify the client's proof-of-work the service MUST do the following steps: