11 KiB
Compatibility with Python Reticulum
Reference target
Reticulum-Go is tested against Python RNS 1.5.2, plus the official network API reference.
Crossref vectors clone the reference from rns://7649a50d84610232d1416b41d2896aff/reticulum/reticulum via rngit (tests/crossref/run_crossref.sh). The GitHub mirror is not used for vectors.
The detailed matrix with config key tables lives in COMPATIBILITY.md. This page summarizes the key differences and design choices.
Component parity
| Component | Status | Notes |
|---|---|---|
| Crypto | Complete | Curve25519, AES-256-CBC, HMAC-SHA256, HKDF. Crossref verified |
| Identity | Complete | Optional RHB1 hardware descriptor. Python from_file is 64-byte software only. Known-peer ratchets persist under storage/ratchets/ |
| Destination | Complete | SINGLE, GROUP, PLAIN, LINK. Identity ratchets opt-in via EnableRatchets. GROUP uses shared Token keys (CreateKeys / LoadPrivateKey) |
| Packet | Complete | Header types 1 and 2, all packet types and contexts |
| Transport | Complete | Path table, announces, relay, persistence, ingress control, random-blob path selection |
| IFAC | Complete | UDP, TCP, Auto. Live tests in tests/interop/ifac_live_test.go |
| Link | Complete | Both directions, RTT, request/response, channel, buffer, resources |
| Resource | Complete | Multi-part, hashmaps, RESOURCE_PRF, bzip2, split advertisements |
| Channel | Complete | Ghost-envelope fix, RX sequence ring, TX window and MDU gates. Tests in pkg/channel |
| Buffer | Complete | Stream buffer over channel |
| Interfaces | Partial | See below |
| Discovery | Complete | Wire, listen, announcer, LXStamper, autoconnect for Backbone, TCP, and I2P when autoconnect_discovered_interfaces > 0 |
| Blackhole | Complete | Local table, announce drop, LINKIDENTIFY teardown, publish /list, sources updater |
| Node lifecycle | Go-only | pkg/node embedder API, no Python equivalent |
| librns C ABI | Go-only | pkg/librns, include/rns.h. See librns |
| Odin librns bindings | Go-only host | bindings/odin (Linux). See librns |
| Dart librns FFI | Go-only host | bindings/dart. Linux, Android, Windows. See librns |
| Dart Control API client | Go-only host | bindings/dart. See Control API |
Interfaces
| Python | Reticulum-Go |
|---|---|
| UDPInterface | Yes |
| TCPClientInterface, TCPServerInterface | Yes |
| AutoInterface | Yes (includes 1.3.5 roam listener swap) |
| I2PInterface | Yes |
| BackboneInterface | Yes |
| RNode, KISS, AX25KISS, Weave | No |
| SerialInterface | Yes |
| Modem73Interface | Yes |
| SDRInterface | Yes (lab/testing Go-native burst modem, mock/rtltcp, optional tagged USB backends) |
| PipeInterface | Yes |
| LocalInterface | Yes via share_instance and config LocalInterface / LocalServerInterface |
| External plugins | Yes (Go-native factories, manifests, executables under interfaces/) |
| WebSocket | Go-only |
| QUIC | Go-only (QUICClientInterface / QUICServerInterface) |
| WebTransport | Go-only (WebTransportClientInterface / WebTransportServerInterface) |
| DNSRendezvous | Go-only (DNSRendezvousInterface) |
| VSOCK | Go-only Linux (VSOCKClientInterface / VSOCKServerInterface) |
| HTTPS | Go-only (HTTPSClientInterface / HTTPSServerInterface) |
UDP requires explicit target_host or target_address (Python forward_ip policy).
Opt-in UDP reconnect when max_reconnect_tries > 0 is a Go extension.
Python 1.2.x to 1.4.2 changes
Wire format is stable across 1.2.x to 1.4.x. Notable behavior differences:
| Python change | Version | Go |
|---|---|---|
| BZ2 bomb limits | 1.1.9 | Covered |
| Path-request ingress/egress control | 1.2.5 | Covered |
| Path table random-blob selection | 1.2.x+ | Covered |
| Announce dedup when dest in path table | 1.3.4 | Covered |
| Blackhole link teardown at LINKIDENTIFY | 1.3.2 | Covered |
| AutoInterface roam listener replacement | 1.3.5 | Covered |
| Channel ghost envelopes | 1.3.0 | Covered |
| Channel RX sequence ring and send window/MDU | Python Channel | Covered |
| Shared-instance RPC msgpack | 1.3.4 | Covered |
| MODE_INTERNAL / recursive_prs / announce mode rules | 1.3.6 | Covered |
| Ephemeral transport identity / static_transport_identity | 1.3.6 | Covered |
| local_hops_delta hop mangling | 1.3.6 / 1.3.7 | Covered |
| Reject unpack when hops >= PATHFINDER_M | 1.3.8 | Covered |
| Link expected_hops on both sides / LRPROOF hop gate | 1.3.8 | Covered |
| Discovery on MODE_INTERNAL / location_cmd | 1.3.9 | Covered |
| LINKIDENTIFY once / receiver RESOURCE_RCL | 1.3.9 | Covered |
| Resource ADV size / empty HMU / Backbone flap block | 1.3.9 | Covered |
| Default discovery stamp 16 / stamp caches | 1.4.0 | Covered |
| Link keepalive when remote continuously transmits | 1.4.0 | Covered (lastKeepaliveNs) |
| Backbone blocked_ips / blocked_ip_list in ifstats | 1.4.0 | Covered |
| Known-destination background cleaning | 1.4.0 | Covered (Go path/age rules) |
| Interface gravity contests | 1.4.1 | Covered (Go pathingAffinity unique) |
| announces_to_internal / boundary search modes | 1.4.1 | Covered |
| LRPROOF path rebalance | 1.4.1 | Covered (Go dampening + gravity sticky) |
| max_request_size / max_response_size | 1.4.1 | Covered |
| Recursive PR online gate | 1.4.2 | Covered (Go also bitrate-gates + emit re-check) |
| Discovery blackhole filtering | 1.4.2 | Covered (mutation-invalidated set, receive-time drop) |
Known gaps
| Gap | Impact |
|---|---|
| Discovery TCPClient/I2P autoconnect | Go implements TCP client and I2P peer autoconnect from discovery. Python still stubs these paths |
| Remote management mutate | Remote /path table and rates plus /status work. Remote drop, path-request, and blackhole mutate are unimplemented (Python also exits 255) |
| RNode and radio serial drivers | RNode / KISS / AX25 / Weave not in this tree. SerialInterface, Modem73Interface, and SDRInterface are present |
| Utilities rnir rnpkg | Not ported |
| rngit | Ported (reticulum-go git, git-remote-rns) |
| Python-only utilities | rnir, rnpkg, rnodeconf are not ported |
Go-only extensions
These do not change the wire format:
| Feature | Package / location |
|---|---|
| Interface hot reload | pkg/node/reload.go, SIGHUP |
| watch_interfaces NIC polling | pkg/node/netmon.go |
| Node lifecycle API | OnNetworkAvailable, OnNetworkLost, RefreshPaths |
| UDP reconnect (opt-in) | pkg/interfaces/reconnect.go |
| Backbone I/O multiplexing | pkg/backbone |
| WebSocket interface | pkg/interfaces/websocket_*.go |
| QUIC interface | pkg/interfaces/quic.go, quic_tls.go |
| Control API | pkg/controlapi |
| librns C ABI | pkg/librns, include/rns.h (librns) |
| Odin librns bindings | bindings/odin (librns) |
| Zig librns bindings | bindings/zig (librns) |
| C++ librns bindings | bindings/cpp (librns) |
| Dart librns FFI | bindings/dart (librns) |
| Dart Control API client | bindings/dart (Control API) |
| Runtime sandbox | pkg/sandbox |
| Sandbox profiles and extra paths | sandbox_profile, sandbox_extra_paths, sandbox_strict, sandbox_exec_rlimits |
| Control API Unix socket | control_api_socket in addition to TCP |
| Local mesh health counters | pkg/health, status RPC fields, reticulum-go slow findings |
| Pathing affinity / rebalance dampening | Gravity contests use live iface penalty. LRPROOF rebalance capped per dest and gravity-sticky |
| Local DoS protection | pkg/protect, config dos_protection (off/detect/prevent/auto), storage/dos_protect.mpack |
| RAM-only path tables | in_memory_path_table, in_memory_known_destinations |
| Fully ephemeral storage | in_memory_storage, RETICULUM_IN_MEMORY_STORAGE, soft caps |
| Stream read chunk | 64 KiB socket reads on TCP/QUIC/VSOCK/WebTransport/I2P/Local/Pipe/backbone. Packet MTU unchanged |
| HandlePacket worker pool | Fixed workers and bounded queue (max_packet_handlers). Overflow always sheds |
| node_profile | default, core_router, embedded. Fills unset knobs only |
| Packet hashlist | Compact open-addressing generations. Rotate at max/2. Default 1M when transport is on |
Config differences
| Topic | Python | Reticulum-Go |
|---|---|---|
| Default config dir | ~/.reticulum, /etc/reticulum | ~/.reticulum-go |
| Parser | configobj | Hand-rolled in pkg/reticulumconfig |
| Unknown keys | Errors | Ignored |
| Comments | # | # and ; |
| Identity storage | Per-name blobs | Per-hash blobs (loads Python known dest files) |
| Log destination | stdout / file / callback | stderr, file, both, syslog, journald (and combinations) |
Utilities
| Python | Reticulum-Go |
|---|---|
| rnsd | reticulum-go daemon |
| rnstatus | rgostatus (same RPC and remote -R dest as Python, extra Go integrity fields) |
| (none) | rgoslow / reticulum-go slow (bottleneck and local health findings, Go-only) |
| (none) | rgozen / reticulum-go zen (static path and link footgun scan for Go and optional Python, Go-only) |
| Examples/Speedtest.py | rgospeed / reticulum-go speedtest (loopback link throughput smoke) |
| rnid | rgoid (.rid/.rsg/.rsm/.rfe compatible) |
| rnprobe | rgoprobe |
| rnpath | rgopath (same RPC and remote -R dest as Python) |
| rncp | rgocp (send/listen/fetch on rncp.receive) |
| rnir, rnodeconf, rnpkg | Not ported (deferred post-1.0). rnx is reticulum-go x. rngit is reticulum-go git |
| rnsh | Python rnsh talks to a Go listener on dest app rnsh. reticulum-go sh auto-detects that dest. Native rgosh dest is Go-only. Listen -b PERIOD / -A / -C match Python rnsh. Unix PTY. Windows listener is pipes only. |
| WASM | reticulum-wasm (Go-only) |
| librns | librns.so + rns.h (Go-only, Linux first) |
| Odin bindings | bindings/odin (links librns.so, librns) |
| Dart client | bindings/dart (rns_control FFI and Control API) |
Setup for mixing Python and Go tools against either daemon is documented in CLI utilities.
Verification workflow
# Unit and package tests
make test
# Crossref against Python vectors
./tests/crossref/run_crossref.sh all
# Live Go/Python side by side
RUN_LIVE_INTEROP=1 go test -v ./tests/interop/...
Running alongside Python
Use separate config directories (~/.reticulum-go vs ~/.reticulum). Point interfaces at the same peers with matching IFAC and ports. Shared instance ports must not conflict if both try to own the same interface.
To let rgostatus query Python rnsd, point -config at ~/.reticulum and align rpc_key when set. On Linux both stacks default to Unix RPC when shared_instance_type is unset. Go tools also fall back to TCP when the type is unset. See CLI utilities.
Related documents
- COMPATIBILITY.md full tables
- CLI utilities for Go CLI tools and RPC setup
- Interfaces
- Cryptography
- Development and testing