A peer-to-peer network for the sovereign age.
Rings is a browser-native, structured peer-to-peer network for applications that need their own network layer instead of a server-owned data path. Browser tabs and native daemons can join the same overlay, discover peers by DID, and exchange messages over direct WebRTC datachannels routed by a Chord DHT.
The threat model and the contract of each layer are documented in
SECURITY.md. DID authentication proves key control; it is not, by
itself, Sybil or eclipse resistance for permissionless public membership. The overlay
routes and, after an E2E handshake, encrypts; it does not hide who is talking to whom.
That is the job of the privacy layer, the onion circuits in crates/node/src/onion.
At the application layer, Rings gives developers a namespace-scoped protocol runtime: write a pure state machine, attach an interpreter shell, and run it over a decentralized overlay. Built-in protocols cover peer service relay and echo; the roadmap extends both the network layer and the privacy layer.
The canonical protocol paper is maintained in this repository:
If you cite Rings in academic or technical writing, use:
@misc{rings-network,
author = {Ryan J. Kung},
title = {Rings: A peer-to-peer network for sovereign age},
year = {2023},
month = feb,
url = {https://github.com/RingsNetwork/rings/blob/master/papers/rings.pdf},
note = {Repository-owned whitepaper and LaTeX source: https://github.com/RingsNetwork/rings/tree/master/papers}
}Rings runs in browsers through WebAssembly and web_sys, and on native hosts through
the same Rust node stack. WebRTC datachannels carry peer-to-peer traffic, including
browser-to-browser connections without an application server in the data path.
Peers are addressed by decentralized identifiers backed by selectable signature schemes, including secp256k1, secp256r1, ed25519, BLS, and bip137. This lets Rings bridge browser, daemon, and wallet-oriented identity workflows without binding the network to one key system. See the threat model for the boundary between DID authentication and Sybil resistance.
The overlay uses a Chord DHT for successor/finger-table routing, DID lookup, message
relay, stabilization, and network_id isolation. Independent overlays stay separate
while retaining deterministic routing behavior. Chord routing assumes an acceptable
membership model; see the overlay threat model.
Onion circuits in crates/node/src/onion carry traffic over
direct edges through layered ElGamal-AEAD frames, fixed-batch cover cells with pacing,
and fixed cell size classes. A circuit hides the route's hops from one another and hides
the client from the exit. It does not hide the client from its first hop, does not hide
overlay membership, and does not hide activity timing from an observer that watches
every link. The plain overlay relay offers none of this: it minimizes what it leaks, and
the privacy layer is where privacy is provided. See
the layer contracts.
Application protocols are namespace-scoped. A protocol's step function stays pure,
and all side effects are performed by its Interpret shell through a scoped capability.
That keeps protocol logic extensible without adding a global effect bus to the core.
You can install rings-node either from Cargo or from source.
Install the rings CLI from crates.io:
cargo install rings-nodeInstall the CLI from a local checkout:
git clone git@github.com:RingsNetwork/rings.git
cd ./rings
cargo install --path crates/nodeBuild the browser provider with Cargo and wasm-bindgen:
cargo build -p rings-node --release --target wasm32-unknown-unknown --no-default-features --features browser
wasm-bindgen --out-dir pkg --target web ./target/wasm32-unknown-unknown/release/rings_node.wasmOr build with wasm-pack:
wasm-pack build --scope ringsnetwork -t web crates/node --no-default-features --features browser,console_error_panic_hookrings --helpThe browser and extension frontend lives in frontend. It is the
user-facing Rings web surface for the landing page, the guide,
the browser node console, onion proxy WorkBench, wallet login, SDP/HTTP connectivity,
topology, and custom messages.
Runnable examples live in examples/:
| Example | What it shows |
|---|---|
native |
A minimal native node registering a custom namespaced protocol |
relay |
TCP & UDP tunnels to a peer's service over the overlay (tcp.rs / udp.rs) |
dweb |
A decentralized-web app (Yew / Trunk) |
ffi |
Driving a node over the C FFI |
A protocol is a pure state machine; all IO lives in its interpreter shell, which can only act within its own namespace. Inbound overlay messages are routed to a protocol by namespace.
// Register a pure Protocol + its Interpret shell, then route inbound envelopes to it.
provider.register_protocol(Echo, EchoShell)?;
provider.set_backend()?;
// Built-in relay: tunnel a local socket to a peer's service over the overlay — no server.
let relay = RelayHandle::install(&provider.extensions())?;
relay.register_tcp_service("web".into(), "example.com:80".parse()?).await?; // server side
relay.open_tcp_tunnel(local_addr, peer_did, "web".into()).await?; // client sideIn the browser a protocol can be a JS handler instead: provider.on(namespace, initialState, handler). See examples/relay and
crates/node/src/extension.
Proof systems use the same user-owned protocol boundary: register a private namespace, encode versioned proof requests and results as application payloads, and perform proving or verification in the protocol interpreter. Rings authenticates and routes the envelope but does not select, execute, or maintain a proving backend.
| Resource | Link | Notes |
|---|---|---|
| Rings Whitepaper | PDF, LaTeX source, citation | Canonical protocol paper |
| Security model | SECURITY.md | Overlay assumptions, deployment models, Sybil boundary, and the communication-layer / privacy-layer contracts |
| Browser frontend | frontend |
Landing guide, web app, and extension workflow |
| Documentation | rings.rs/docs, source | mdBook book, published with the site |
| Guide | rings.rs/#guide | One card per runtime with the first commands; the book is the reference |
| For AI agents | rings.rs/llms.txt, source | Project map for coding agents (llms.txt), maintained with the code |
| Examples | examples/ |
Native, dweb, relay, and FFI examples |
| X (Twitter) | @RingsNetworkio | Project announcements |
-
core: DHT, swarm, DID routing, messages, and cryptographic identity primitives.
-
node: Native daemon, browser/WASM provider, extension runtime, relay protocol, and FFI provider.
-
rpc: Rings RPC shared types and the JSON-RPC client/handlers (over HTTP).
-
derive: Rings macros, including
wasm_exportmacro. -
transport: Native WebRTC transport and
web_sys-based browser transport.
Rings is layered so that every layer is decentralized — there is no server in the data path. This is a data-path topology statement, not a permissionless Sybil-resistance claim; see SECURITY.md. Each layer maps directly to a crate/module:
┌──────────────────────────────────────────────────────────────────────┐
│ Applications dWeb · relay/tunnel · your own app │
├──────────────────────────────────────────────────────────────────────┤
│ Protocols built-ins: relay (tcp/udp tunnels), echo — │ node::extension::protocols
│ (namespaced) plus any user Protocol, addressed by namespace │
├──────────────────────────────────────────────────────────────────────┤
│ Extension pure `Protocol::step` → `Effect` → `Interpret` shell │ node::extension::ext
│ runtime over a namespace-scoped `Scope` (send / self-inject) │
├──────────────────────────────────────────────────────────────────────┤
│ Privacy onion circuits: layered ElGamal-AEAD over direct │ crates/node/src/onion
│ (circuits) edges, fixed-batch cover + pacing, exit registry │
├──────────────────────────────────────────────────────────────────────┤
│ Overlay Chord DHT: successor / finger tables, stabilization, │ crates/core
│ (routing + DID addressing, message relay, network_id isolation, │
│ encryption) E2E ElGamal to a DID after its handshake │
├──────────────────────────────────────────────────────────────────────┤
│ Transport direct WebRTC datachannels (native + browser/web_sys), │ crates/transport
│ STUN / ICE / SDP NAT traversal │
├──────────────────────────────────────────────────────────────────────┤
│ Identity DID + secp256k1 / secp256r1 / ed25519 / BLS / bip137 │ crates/core::ecc
└──────────────────────────────────────────────────────────────────────┘
- Transport establishes direct, peer-to-peer WebRTC datachannels — browser-to-browser
included — using STUN/ICE/SDP for NAT traversal, so traffic never transits a central server.
Native nodes deployed behind cloud firewalls can bound ICE UDP gathering with
external_ip,webrtc_udp_port_min, andwebrtc_udp_port_max; for example,49160..=49200maps to an AWS security-group rule forUDP 49160-49200. Browser nodes still use the browser ICE stack, whose local UDP ports are not controlled by Rings. - Overlay organizes peers into a Chord DHT and routes messages by DID; distinct overlays are
isolated by
network_id. Its contract is routing and confidentiality only: a payload can be encrypted to the destination's account key once the E2E handshake has supplied that key, but every hop sees the origin DID by signature and the destination DID by routing. The overlay minimizes what it leaks; it does not provide privacy. - Privacy is the onion circuit data plane: layered ElGamal-AEAD frames over direct edges, fixed-batch cover cells with pacing, fixed cell size classes, and route selection from the onion-relay and onion-exit registries. Each relay learns its predecessor and its successor and nothing else about the route. See SECURITY.md.
- Extension runtime is a functional core / imperative shell: a protocol's state transition
is pure (
step), and all IO happens in itsInterpretshell, which only ever receives a namespace-scoped capability (Scope). The core owns no global effect/command bus — adding a protocol never touches it, and a protocol cannot reach another namespace. - Protocols are addressed by namespace. Built-ins include a relay that tunnels local
TCP/UDP sockets to a peer's service across the overlay (server-less tunneling / peer exit), and
an echo protocol used by examples and tests. Register your own with
provider.register_protocol(..)(Rust) orprovider.on(namespace, ..)(JS).
The privacy layer exists today as crates/node/src/onion; where it and the network layer
are heading — a fully server-less, sovereign network — is described in ROADMAP.md.
We welcome contributions to rings-node!
If you have a bug report or feature request, please open an issue on GitHub.
If you'd like to contribute code, please follow these steps:
Fork the repository on GitHub.
Create a new branch for your changes.
Make your changes and commit them with descriptive commit messages.
Push your changes to your fork.
Create a pull request from your branch to the main repository.
We'll review your pull request as soon as we can, and we appreciate your contributions!
Rings is released under the GNU Affero General Public License, version 3.0 only (AGPL-3.0-only). Works derived from it must be released under the same license, and the AGPL's network clause extends that obligation to services that offer Rings over a network: a product or hosted service built on Rings must publish its source.
A commercial license for use outside the AGPL's terms is available from Rings Network on request. The Rings Network name, logo, and the hosted rings.rs service are not covered by the software license.