BitTorrent (BEP) compliance of gx-core¶
Support status for the BitTorrent specifications (BEPs) of the gx-core engine
(internal/gxcore) and the gx-torrent daemon (cmd/gx-torrent).
This document is the single source of truth for BEP status: the status reflects
the code, not comparisons with other clients. The per-file detail is in
internal/gxcore/GEXTTO.md (engine inventory)
and in gx-torrent.md (daemon); rationale, measurements and
backlog in todo.md.
Status legend: yes = implemented and tested; partial = only a part; no = absent; excluded = out of scope by choice.
Long explanations are kept in the notes below each table, so that the columns stay narrow and the tables remain readable.
Peer wire and metadata¶
| BEP | Specification | Status |
|---|---|---|
| 3 | The BitTorrent Protocol Specification (core TCP/UDP wire) | yes |
| 4 | Reserved bits in the handshake | yes |
| 6 | Fast Extension (have all/have none, suggest, allowed fast) |
yes |
| 9 | ut_metadata (metadata from magnet) |
yes |
| 10 | Extension Protocol (handshake m) |
yes |
| 11 | Peer Exchange (ut_pex, IPv4 + added6/dropped6) |
yes |
| 12 | Multitracker Metadata Extension (tiered announce-list) |
yes |
| 14 | Local Service Discovery (LSD, IPv4 and IPv6) | yes |
| 16 | Super-seeding (initial seeding, one piece at a time) | yes |
| 19 | WebSeed ("GetRight style", HTTP Range) | yes |
| 20 | Peer ID Conventions | yes |
| 21 | Extension for Partial Seeds (upload_only, event=paused) |
yes |
| 23 | Compact Peer Lists for Trackers | yes |
| 24 | Tracker Returns External IP (ip) |
yes |
| 27 | Private Torrents (private: 1, no DHT/PEX/LSD) |
yes |
| 38 | Finding Local Data Via Torrent File Hints (similar/collections) |
yes |
| 40 | Canonical Peer Priority (tie-break) | yes |
| 47 | Padding Files (.pad/) |
yes |
| 54 | The lt_donthave extension (a peer no longer has a piece) |
partial (reception) |
BEP 38 (
similar/collections). The hints are read from the info dictionary and from the top level (merged, deduplicated), re-emitted in the.torrentexport and shown together with the local torrents that share a hint. The reuse of the shared data — the point of the BEP — is Swarm Merging, which is not driven by the hints but by the structure (an identical piece layout, or an equal v2 per-file Merkle root): matching on the identity of the bytes is what makes the reuse safe. Phases 1–3 are done (the Swarm Merging section ingx-torrent.mdandmeasurements.md), including block-granularity reuse, the resume path and the re-trigger when a sibling appears after the allocation. The daemon's BEP 38 view isGET /api/v1/torrents/{hash}/collections.BEP 54 (
lt_donthave). Implemented on the reception side and advertised in the BEP 10 handshake: a peer that drops a piece it had announced has its availability cleared and the in-flight fetch cancelled (without the fast extension; with it, the peer rejects the request individually). Sending is intentionally not implemented: gx-core never revokes a verified piece — there is no piece eviction or discard path — so the only honest trigger for adonthave(dropping data it told a peer it had) never occurs. If such a path is ever added, the extension is already negotiated and the message type exists (peerprotocol.DontHaveMessage); hence partial, notno.
Transport, encryption and NAT¶
| BEP | Specification | Status |
|---|---|---|
| 29 | uTP (uTorrent Transport Protocol) | yes |
| 55 | Holepunch Extension (ut_holepunch over uTP) |
yes |
| — | MSE/PE (Protocol Encryption, de-facto) | yes |
Trackers¶
| BEP | Specification | Status |
|---|---|---|
| 7 | IPv6 Tracker Extension (peers6) |
yes |
| 15 | UDP Tracker Protocol (connect/announce/scrape) | yes |
| 31 | Tracker Failure Retry Extension | yes |
| 41 | UDP Tracker Protocol Extensions (URLData, option 0x2) |
yes |
| 48 | Tracker Scrape (HTTP /scrape and UDP) |
yes |
| 34 | DNS Tracker Preferences (SRV records) | no |
BEP 31 honours
retry in(in minutes) andnever;neverdrops the tracker from the tier.BEP 34 (DNS Tracker Preferences) is not implemented: it lets a tracker host advertise its endpoints as SRV records (
_udp.…,_http._tcp.…) so a client can find a tracker without a literalhost:port. Almost no public tracker publishes SRV records, and the ones that do are also reachable through their normal announce URL, so the feature would add a DNS dependency and a second discovery path for a case that does not occur in practice.
DHT (Mainline / BEP 5)¶
| BEP | Specification | Status |
|---|---|---|
| 5 | Mainline DHT Protocol (Kademlia IPv4) | yes |
| 32 | IPv6 Extension for DHT (nodes6, want) |
yes |
| 33 | DHT Scrape (Bloom filters BFpe/BFsd) |
yes |
| 42 | DHT Security Extension (Secure Node ID, CRC32C) | yes |
| 43 | Read-only DHT Nodes (ro: 1) |
yes |
| 44 | Storing arbitrary data in the DHT (K/V Ed25519) | yes |
| 45 | Multiple-address Operation for DHT (multi-homed) | no |
| 46 | Updating Torrents via DHT Mutable Items (urn:btpk:) |
yes |
| 51 | DHT Infohash Indexing (sample_infohashes) |
no |
BEP 42 is complete in both directions: the node ID is derived from the external IP and the
ipfield is read and sent in every response (reflected_sent); theipfield is at the top level of the message, as per the specification and as libtorrent does. BEP 5 honoursimplied_portinannounce_peer.BEP 44 offers a local store, a
get/putresponder and an outgoing iterative client (bounded) to read and publish items; theputgoes to the 8 closest nodes to the target among those that provided a token. The responder treats aputwith any ofk,sig,seqorcasas mutable and refuses it (203) unlessk,sigandseqare all present, so an unsigned value is never stored as immutable by mistake.BEP 46 is reached through the magnet parameter
xs=urn:btpk:, resolved by the BEP 44 client on add.BEP 45 and BEP 51 are deliberately not implemented. BEP 45 (multi-homed DHT) lets a node reachable on several interfaces announce several addresses per family; a home/NAS client with one public address gains nothing from it, and the dual-stack case is already covered by BEP 32 (
nodes6/want). BEP 51 (sample_infohashes) exposes a node's whole infohash index so that crawlers can enumerate the swarm: it is a service for indexers, and it adds a privacy and load surface (the node publishes what it is storing) that a home client neither needs nor wants. Both are marginal for this client, cost > benefit, and stay in Remaining items.
BitTorrent v2 and magnet¶
| BEP | Specification | Status |
|---|---|---|
| 52 | BitTorrent v2 (SHA-256 Merkle trees, piece layers) |
yes |
| 53 | Magnet URI extension: so= (Select Only) |
yes |
BEP 52 covers v1, hybrids and v2-only, both from
.torrentand from magnet. As a seed it answershash requestfor the piece layer from the attachedpiece layersand, for the block layer (base = 0), both for a file present in full and, for the parts already verified, for a partially downloaded file (the requested 16 KiB leaf hashes are computed from the verified pieces and anchored with the piece layer's uncles; a request that touches a missing piece or asks for more than 512 hashes is refused).The magnet parameter
so=is BEP 53.ws=(web seed),xs=(exact source),as=(acceptable source) anddht=(DHT bootstrap node) come from the Magnet URI convention (not from a BEP): gx-core handlesws=,dht=,xs=andas=(withxs=/as=it downloads the.torrentfrom the source, verifying that the info hash matches, so metadata does not depend on the swarm).
How v2 differs from v1 (the rules that matter)¶
- Info-hash: SHA-256 of the info dict; trackers and handshake use the
20-byte truncated form (wire identical to v1); magnets use
urn:btmh:. pieces root: root of a branch-2 Merkle tree over a file's 16 KiB blocks; the last block may be shorter (hash of the actual bytes) and the leaves past the end of the file are 32-byte zero hashes.piece layers(top level, outsideinfo): for eachpieces root, the hash of a layer chosen so that one hash coverspiece lengthbytes; hashes past the end of the file are omitted.- Alignment: files are mapped onto piece boundaries and pieces do not
span two files; the last piece of a file may be shorter than
piece lengthand carries no padding. gx-core therefore uses a per-file piece model (not concatenated with synthetic padding). - Peer extensions:
hash request(21),hashes(22),hash reject(23), used to fetch a peer'spiece layers(BEP 9 carries the info dict). - Hybrids: an info dict with both fields; v1 = SHA-1 and v2 = SHA-256 over the complete dict.
Out of scope / obsolete¶
| BEP / technology | Reason |
|---|---|
| 8 (Tracker Peer Obfuscation) | deferred by the BEP process |
| 17 (HTTP Seeding "Hoffman") | superseded by BEP 19 |
| 18 (Search Engine) / 22 (Local Tracker Discovery) / 26 (Zeroconf) / 28 (Tracker exchange) | deferred |
| 30 (Merkle tree torrent extension, v1) | superseded by BEP 52 (v2) |
| 35 (Torrent signing) | standard that never took off |
| 36 / 39 / 49 (RSS feeds, updating via feed, distributed feeds) | application level: Gextto already has RSS/Torznab |
| 50 (Publish/Subscribe Protocol) | niche (pub/sub over DHT); cost > benefit |
| WebTorrent (WebRTC) | requires the WebRTC stack; external component, not in the core |
| Native I2P SAM | SOCKS5/HTTP proxies can be used; native SAM out of scope |
Remaining items and roadmap¶
- BEP 34 (DNS Tracker Preferences), BEP 45 (DHT multi-address) and
BEP 51 (
sample_infohashes): not implemented by choice — SRV trackers are practically unused, multi-homed DHT is marginal for a single-address home/NAS client (dual-stack is already BEP 32), and infohash indexing is a crawler service with a privacy/load cost. Reasons in the notes above. - 10 Gbps throughput (pipelining): the adaptive request queue already
exists; every change must be measured before and after (CPU, RAM,
throughput), as per the performance rule in
AGENTS.md.
BEP 38 is complete (hints, block reuse at allocation/resume/later trigger):
the detail is in the note above, in gx-torrent.md
(Local data reuse) and in measurements.md.
Beyond the BEPs. Extensions that are not part of the BEP catalogue — the
WebSocket tracker (ws:///wss://), WebTorrent/WebRTC peers, the v1
cross-layout swarm merge and decentralized feeds on BEP 46 — are outside these
tables: bep.md stays the BEP-only source of truth.
Maintenance¶
Update this table on every new BEP implemented or excluded, together with the
linked documents (internal/gxcore/GEXTTO.md,
gx-torrent.md, todo.md); an entrygiven as absent must be closed or reclassified when the code implements it.
Comparison with other clients¶
Support for the BEPs listed above, from each project's own documentation on 2026-10-17. Yes = supported; partial = only part of it; no = documented as absent; – = the project's documentation does not state it (not a claim that it is missing). A client built on libtorrent inherits the library's support: the column covers qBittorrent and Deluge as well.
| BEP | Specification | gx-core | libtorrent (qBittorrent, Deluge) | Transmission 4.x | Rain | anacrolix/torrent |
|---|---|---|---|---|---|---|
| 3 | Core wire protocol | yes | yes | yes | yes | yes |
| 4 | Reserved handshake bits | yes | yes | yes | – | – |
| 5 | Mainline DHT | yes | yes | yes | yes | yes |
| 6 | Fast Extension | yes | yes | yes | yes | – |
| 7 | IPv6 trackers | yes | yes | yes | no | – |
| 9 | Metadata from peers (magnet) | yes | yes | yes | yes | – |
| 10 | Extension Protocol | yes | yes | yes | yes | yes |
| 11 | Peer Exchange | yes | yes | yes | yes | yes |
| 12 | Multitracker | yes | yes | yes | yes | – |
| 14 | Local Service Discovery | yes | yes | yes | – | – |
| 15 | UDP trackers | yes | yes | yes | yes | – |
| 16 | Super-seeding | yes (opt-in) | yes | – | no | – |
| 19 | Web seeds | yes | yes | yes | yes | yes |
| 20 | Peer ID conventions | yes | yes | yes | – | – |
| 21 | Partial seeds | yes | yes | yes | – | – |
| 23 | Compact peer lists | yes | yes | yes | – | – |
| 24 | Tracker returns external IP | yes | yes | – | – | – |
| 27 | Private torrents | yes | yes | yes | – | – |
| 29 | uTP | yes | yes | yes | no | yes |
| 31 | Tracker failure retry | yes | yes | – | – | – |
| 32 | IPv6 DHT | yes | yes | – | no | – |
| 33 | DHT scrape | yes | – | – | – | – |
| 34 | DNS trackers (SRV) | no | no | – | – | – |
| 38 | Local data hints | yes | no | – | – | – |
| 40 | Canonical peer priority | yes | yes | – | – | – |
| 41 | UDP tracker extensions | yes | – | – | – | – |
| 42 | DHT security (secure node ID) | yes | yes | – | – | – |
| 43 | Read-only DHT nodes | yes | yes | – | – | – |
| 44 | DHT key/value store | yes | yes | – | – | – |
| 45 | DHT multi-address | no | – | – | – | – |
| 46 | DHT mutable items | yes | yes | – | – | – |
| 47 | Padding files | yes | yes | – | – | – |
| 48 | Tracker scrape | yes | yes | yes | – | – |
| 51 | DHT infohash indexing | no | no | – | – | – |
| 52 | BitTorrent v2 / hybrid | yes | yes (2.x) | no | – | yes |
| 53 | Magnet: select only | yes | yes | – | – | – |
| 54 | lt_donthave |
partial (reception) | yes | – | – | – |
| 55 | Holepunch | yes | yes | no | – | yes |
| — | MSE/PE encryption | yes | yes | yes | yes | yes |
Reading it. gx-core covers the v1 set and v2/hybrid, with holepunching, super-seeding (opt-in), web seeds, encryption, LSD and IPv6 on trackers and DHT; it also implements BEP 38, 40, 41, 42–44, 46 and 47, which the other clients either leave undocumented or do not implement. Transmission 4.x still has v2 (BEP 52) and BEP 55 as open items (milestone 5.0). Rain is deliberately focused on the server case: its documented set has no uTP, IPv6, super-seeding or v2. For anacrolix/torrent the README names DHT, PEX, uTP, web seeds, v2 and holepunching; the rest is not documented there, so it is marked “–”.
Application-level features (web UI, RSS, search, streaming, APIs) are outside a BEP comparison. Sources: libtorrent 2.x features page and Upgrading to 2.0; the Rain README (Features and Missing features); the anacrolix/torrent README; the Transmission issue tracker (v2 #458, BEP 55 #3705) and 4.1 release notes; the Deluge 2.2 release notes.