# N2R (node-to-relay) protocol

N2R allows communication between any two nodes, *as long as one of them is a relay*.

## Packet format

The packet format is based on the `InnerPacket` Rust enum:

```rust
/// Represents the actual end-to-end packet that is carried in the payloads. Either an application-level message, or a batch of reply blocks.
pub enum InnerPacket {
    /// Normal messages
    Message(Message),
    /// Reply blocks, used to construct relay->anon messages
    ReplyBlocks(Vec<ReplyBlock>),

/// An inner packet message with corresponding UDP port-like source and destinaton docks
pub struct Message {
    pub source_dock: Dock,
    pub dest_dock: Dock,
    pub body: Vec<Bytes>,
}

pub type Dock = u32;
```

An `InnerPacket` is stuffed into the 8192-byte payload by this process:

1. First, we encode the packet using [bincode](https://docs.rs/bincode/latest/bincode/), getting `box_plaintext`.
2. We then box-encrypt using an ephemeral keypair, whose public half is `box_epk`, getting `box_ciphertext`.
3. We sign `box_epk` with our identity secret key `identity_sk`, whose public half is `identity_pk`, producing `identity_signature`
4. We then package everything into a tuple `(identity_pk, identity_signature, box_ciphertext)`, bincode it, and pad it to 8192 bytes.

This picture roughly illustrates the structure of a fully encoded `InnerPacket` that stores a normal `Message`.

![](/files/XuN5Ek5jt9iVIp7x8quQ)

## Socket abstraction

The typical interface exposed by N2R is not raw functions for sending and receiving packets. Instead, we use a *socket* abstraction inspired by UDP. Each socket represents an `Endpoint`, a *local fingerprint:dock pair,* that can receive and send messages. More specifically:

* The user constructs a socket by **binding** to an identity and a dock number.
  * This identity can either be the long-term identity of the node, or a temporary anonymous identity.
* The socket has a method to **send** a message to a fingerprint and dock number.
  * This formats a message with:
    * source identity public key and source dock number taken from the identity and dock number of the socket
    * destination identity looked up by fingerprint
  * If the socket is bound to a temporary identity, reply blocks must be sent to the destination fingerprint as well so that they can talk back to us.
* There's also a **receive** method, which returns a message and a source endpoint, which consists of a fingerprint and a dock number.
  * This blocks until there is an incoming message addressed to the identity and dock number that the socket is bound to.
  * In the implementation, there must be some sort of demultiplexing done to separate incoming messages addressed to different sockets.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.earendil.network/wiki/protocols/n2r-protocol.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
