Privacy is a beautiful thing.

But trying to run a globally secure, decentralized anonymity network when almost all your speed test nodes are sitting comfy inside high-speed European and American datacenters is just pure delusion.

We end up with a network that looks blazing fast on paper to a developer in Frankfurt, while being a total, lagging nightmare for real users in Johannesburg, Mumbai, or Singapore. T_T

The issue isnt the onion routing protocol itself.

It is our massive geographic measurement bias.

Since traditional directory authorities and bandwidth scanners are heavily concentrated in the global north, our path selection algorithms get completely skewed metrics.

To prove this, I set up a global measurement mesh using GCE Spot VMs acting as probing agents across ten distinct regions.


The Probe Mesh Architecture

Each agent ran a custom test engine designed to bypass standard Tor path selection and benchmark individual relays directly.

The approach is simple but elegant:

  • Exit Relays: Tested using a single-hop circuit directly from the agent to the exit relay.
  • Guard/Middle Relays: Tested using a two-hop circuit through the target non-exit relay to a calibrated, stable helper exit relay.
graph TD
    Co[Central Coordinator] -->|Distribute Targets| MA1[europe-west1 - Frankfurt]
    Co -->|Distribute Targets| MA2[africa-south1 - Johannesburg]
    Co -->|Distribute Targets| MA3[asia-northeast1 - Tokyo]
    Co -->|Distribute Targets| MA4[southamerica-east1 - São Paulo]

    MA1 -->|1-Hop or 2-Hop Circuit| Tor[Target Tor Relays]
    MA2 -->|1-Hop or 2-Hop Circuit| Tor
    MA3 -->|1-Hop or 2-Hop Circuit| Tor
    MA4 -->|1-Hop or 2-Hop Circuit| Tor

To isolate the target relay’s throughput, each agent VM hosted a local 10MB test file populated with non-compressible random data from /dev/urandom.

The agent forces a circuit, requests its own file, and measures the Time To First Byte (latency) and total throughput.


Let’s Look at the Real BigQuery Telemetry

Over a three-day sprint, the mesh logged over a million individual test runs.

Decompressing the raw data.gz export, we can pull out actual JSON Lines records that show exactly what is going on.

Here is a successful two-hop test from our Johannesburg agent (africa-south1) benchmarking a guard node in the Netherlands:

{
  "measured_at": "2025-06-08 01:23:48.767695 UTC",
  "relay_fingerprint": "AAA7DA4D258D055780F4EE496D1154238DF75E04",
  "relay_nickname": "as215248",
  "country_code": "nl",
  "asn_number": 215248,
  "asn_name": "Bastiaan Mathijs Brink",
  "ip_version_used": "IPv4",
  "is_exit_relay": false,
  "is_guard_relay": true,
  "download_throughput_mbps": 7.05045,
  "latency_ms": 851,
  "test_file_url": "http://34.35.91.131/test10m.dat",
  "bytes_downloaded": 10485760,
  "duration_ms": 11897,
  "circuit_path": [
    "$AAA7DA4D258D055780F4EE496D1154238DF75E04~as215248",
    "$F381C9A8E6F30F6897ADEE5BB28ECFA17671A5D0~FreedomBits1"
  ],
  "calibration_exit_fingerprint": "F381C9A8E6F30F6897ADEE5BB28ECFA17671A5D0",
  "calibration_duration_ms": 10372,
  "effective_throughput_mbps": 55.00726,
  "agent_gcp_region": "africa-south1"
}

Now contrast that with an absolute trainwreck of a run.

During the sweep, the designated Singapore exit helper (5BAC03B8F6BB6A42B194F27C5958941BB2CC5DFD) went completely dark.

As a result, every single two-hop test from the Singapore agent (asia-southeast1) trying to use that helper got blasted with circuit timeouts:

{
  "measured_at": "2025-06-08 01:23:50.897424 UTC",
  "relay_fingerprint": "CF9BEB3E3554C5C343024641A91CC9AE6B849882",
  "relay_nickname": "vunreteqrado",
  "is_exit_relay": false,
  "is_guard_relay": true,
  "download_throughput_mbps": 0.0,
  "latency_ms": 0,
  "error_message": "Failed to extend circuit: custom EXTENDCIRCUIT command failed: 552 No such router \"5BAC03B8F6BB6A42B194F27C5958941BB2CC5DFD\"",
  "calibration_exit_fingerprint": "5BAC03B8F6BB6A42B194F27C5958941BB2CC5DFD",
  "calibration_duration_ms": 9287,
  "agent_gcp_region": "asia-southeast1"
}

This structural failure highlights how fragile distributed active probing can be if your helper nodes arent perfectly stable.


The Global Performance Gap

When we group and aggregate the full dataset by probing region, the disparity is wild.

The numbers don’t lie.

Probing Region Avg Throughput (Mbps) Avg Latency (ms) Failure Rate (%)
europe-west1 (Frankfurt) 22.61 293.30 4.40
us-west1 (Oregon) 9.35 745.76 6.16
us-central1 (Iowa) 8.85 2839.54 29.30
us-east1 (Virginia) 6.65 5181.52 46.82
africa-south1 (Johannesburg) 6.52 1171.03 18.79
southamerica-east1 (São Paulo) 5.32 1291.20 6.24
asia-northeast1 (Tokyo) 5.09 1530.39 8.44
australia-southeast1 (Sydney) 4.46 1321.84 13.86
asia-southeast1 (Singapore) 4.42 1498.57 46.38
asia-south1 (Mumbai) 2.32 7773.50 37.96

Looking closely, Europe is living in the fast lane with an average throughput of 22.61 Mbps and sub-300ms latency.

Meanwhile, Mumbai is crying with 2.32 Mbps throughput and latencies approaching 8 seconds! T_T

The failure rate in Singapore (46.38%) and US East (46.82%) also shows how network paths crumble when specific geographic links are congested or helper exit nodes drop off.


Decentralizing the Observers

If path selection weight depends on performance, and the only scanners that matter are located in Frankfurt and Oregon, Tor will keep prioritizing circuits that are fast for those scanners.

This creates a self-fulfilling loop.

Relays in South America, APAC, and Africa are heavily under-measured and under-allocated, while the northern pipes get severely congested.

If we want a truly resilient anonymity network, we must push the Tor Project to deploy geographically diverse directory scanners.

Privacy shouldn’t have a geographic bias.

If you are writing a paper or planning to replicate this, grab the data.gz dump and analyze it.

Just be prepared for the egress costs; pushing 10MB per test at this scale eaten up roughly 300 USD per day in GCP data transfer rates. ;)