Compare commits

...

15 Commits

Author SHA1 Message Date
Mark Qvist 719764fd81 Updated documentation 2021-05-20 22:35:10 +02:00
Mark Qvist 5ccbc825fd Updated examples 2021-05-20 22:31:09 +02:00
Mark Qvist ad67c553d7 Added exception when trying to remember an invalid public key 2021-05-20 22:30:54 +02:00
Mark Qvist d68cfaa8f7 Optimised link establishment 2021-05-20 20:32:08 +02:00
Mark Qvist cf9934810b Updated documentation 2021-05-20 18:37:59 +02:00
Mark Qvist e8ca88377a Updated documentation 2021-05-20 18:37:12 +02:00
Mark Qvist bf410e006f Updated docs 2021-05-20 17:18:38 +02:00
Mark Qvist db527b6759 Optimised announces to 151 bytes 2021-05-20 16:56:08 +02:00
Mark Qvist 9c995b33dd Updated documentation 2021-05-20 16:06:12 +02:00
Mark Qvist f18fb35aba Updated documentation 2021-05-20 15:31:58 +02:00
Mark Qvist ce405b9252 Migrated all asymmetric crypto operations to ECIES on Curve25519. 2021-05-20 15:31:38 +02:00
Mark Qvist 7f5625a526 Cleanup 2021-05-20 13:38:57 +02:00
Mark Qvist e8fb435f00 Updated link example 2021-05-20 13:37:48 +02:00
Mark Qvist f880edbeb8 Store GROUP destination symmetric key as bytes instead of base64 2021-05-20 12:44:12 +02:00
Mark Qvist 2b97c89566 Updated docs 2021-05-20 10:28:58 +02:00
35 changed files with 1004 additions and 721 deletions
+1 -1
View File
@@ -39,7 +39,7 @@ def program_setup(configpath, channel=None):
# We specify a callback that will get called every time # We specify a callback that will get called every time
# the destination receives data. # the destination receives data.
broadcast_destination.packet_callback(packet_callback) broadcast_destination.set_packet_callback(packet_callback)
# Everything's ready! # Everything's ready!
# Let's hand over control to the main loop # Let's hand over control to the main loop
+4 -4
View File
@@ -52,7 +52,7 @@ def server(configpath):
# Tell the destination which function in our program to # Tell the destination which function in our program to
# run when a packet is received. We do this so we can # run when a packet is received. We do this so we can
# print a log message when the server receives a request # print a log message when the server receives a request
echo_destination.packet_callback(server_callback) echo_destination.set_packet_callback(server_callback)
# Everything's ready! # Everything's ready!
# Let's Wait for client requests or user input # Let's Wait for client requests or user input
@@ -170,12 +170,12 @@ def client(destination_hexhash, configpath, timeout=None):
# the packet times out. # the packet times out.
if timeout != None: if timeout != None:
packet_receipt.set_timeout(timeout) packet_receipt.set_timeout(timeout)
packet_receipt.timeout_callback(packet_timed_out) packet_receipt.set_timeout_callback(packet_timed_out)
# We can then set a delivery callback on the receipt. # We can then set a delivery callback on the receipt.
# This will get automatically called when a proof for # This will get automatically called when a proof for
# this specific packet is received from the destination. # this specific packet is received from the destination.
packet_receipt.delivery_callback(packet_delivered) packet_receipt.set_delivery_callback(packet_delivered)
# Tell the user that the echo request was sent # Tell the user that the echo request was sent
RNS.log("Sent echo request to "+RNS.prettyhexrep(request_destination.hash)) RNS.log("Sent echo request to "+RNS.prettyhexrep(request_destination.hash))
@@ -189,7 +189,7 @@ def client(destination_hexhash, configpath, timeout=None):
# receives a proof packet. # receives a proof packet.
def packet_delivered(receipt): def packet_delivered(receipt):
if receipt.status == RNS.PacketReceipt.DELIVERED: if receipt.status == RNS.PacketReceipt.DELIVERED:
rtt = receipt.rtt() rtt = receipt.get_rtt()
if (rtt >= 1): if (rtt >= 1):
rtt = round(rtt, 3) rtt = round(rtt, 3)
rttstring = str(rtt)+" seconds" rttstring = str(rtt)+" seconds"
+10 -10
View File
@@ -65,7 +65,7 @@ def server(configpath, path):
# We configure a function that will get called every time # We configure a function that will get called every time
# a new client creates a link to this destination. # a new client creates a link to this destination.
server_destination.link_established_callback(client_connected) server_destination.set_link_established_callback(client_connected)
# Everything's ready! # Everything's ready!
# Let's Wait for client requests or user input # Let's Wait for client requests or user input
@@ -102,7 +102,7 @@ def client_connected(link):
if os.path.isdir(serve_path): if os.path.isdir(serve_path):
RNS.log("Client connected, sending file list...") RNS.log("Client connected, sending file list...")
link.link_closed_callback(client_disconnected) link.set_link_closed_callback(client_disconnected)
# We pack a list of files for sending in a packet # We pack a list of files for sending in a packet
data = umsgpack.packb(list_files()) data = umsgpack.packb(list_files())
@@ -114,8 +114,8 @@ def client_connected(link):
list_packet = RNS.Packet(link, data) list_packet = RNS.Packet(link, data)
list_receipt = list_packet.send() list_receipt = list_packet.send()
list_receipt.set_timeout(APP_TIMEOUT) list_receipt.set_timeout(APP_TIMEOUT)
list_receipt.delivery_callback(list_delivered) list_receipt.set_delivery_callback(list_delivered)
list_receipt.timeout_callback(list_timeout) list_receipt.set_timeout_callback(list_timeout)
else: else:
RNS.log("Too many files in served directory!", RNS.LOG_ERROR) RNS.log("Too many files in served directory!", RNS.LOG_ERROR)
RNS.log("You should implement a function to split the filelist over multiple packets.", RNS.LOG_ERROR) RNS.log("You should implement a function to split the filelist over multiple packets.", RNS.LOG_ERROR)
@@ -125,7 +125,7 @@ def client_connected(link):
# open until the client requests a file. We'll # open until the client requests a file. We'll
# configure a function that get's called when # configure a function that get's called when
# the client sends a packet with a file request. # the client sends a packet with a file request.
link.packet_callback(client_request) link.set_packet_callback(client_request)
else: else:
RNS.log("Client connected, but served path no longer exists!", RNS.LOG_ERROR) RNS.log("Client connected, but served path no longer exists!", RNS.LOG_ERROR)
link.teardown() link.teardown()
@@ -254,18 +254,18 @@ def client(destination_hexhash, configpath):
# We expect any normal data packets on the link # We expect any normal data packets on the link
# to contain a list of served files, so we set # to contain a list of served files, so we set
# a callback accordingly # a callback accordingly
link.packet_callback(filelist_received) link.set_packet_callback(filelist_received)
# We'll also set up functions to inform the # We'll also set up functions to inform the
# user when the link is established or closed # user when the link is established or closed
link.link_established_callback(link_established) link.set_link_established_callback(link_established)
link.link_closed_callback(link_closed) link.set_link_closed_callback(link_closed)
# And set the link to automatically begin # And set the link to automatically begin
# downloading advertised resources # downloading advertised resources
link.set_resource_strategy(RNS.Link.ACCEPT_ALL) link.set_resource_strategy(RNS.Link.ACCEPT_ALL)
link.resource_started_callback(download_began) link.set_resource_started_callback(download_began)
link.resource_concluded_callback(download_concluded) link.set_resource_concluded_callback(download_concluded)
menu() menu()
+17 -7
View File
@@ -44,7 +44,7 @@ def server(configpath):
# We configure a function that will get called every time # We configure a function that will get called every time
# a new client creates a link to this destination. # a new client creates a link to this destination.
server_destination.link_established_callback(client_connected) server_destination.set_link_established_callback(client_connected)
# Everything's ready! # Everything's ready!
# Let's Wait for client requests or user input # Let's Wait for client requests or user input
@@ -76,8 +76,8 @@ def client_connected(link):
global latest_client_link global latest_client_link
RNS.log("Client connected") RNS.log("Client connected")
link.link_closed_callback(client_disconnected) link.set_link_closed_callback(client_disconnected)
link.packet_callback(server_packet_received) link.set_packet_callback(server_packet_received)
latest_client_link = link latest_client_link = link
def client_disconnected(link): def client_disconnected(link):
@@ -149,12 +149,12 @@ def client(destination_hexhash, configpath):
# We set a callback that will get executed # We set a callback that will get executed
# every time a packet is received over the # every time a packet is received over the
# link # link
link.packet_callback(client_packet_received) link.set_packet_callback(client_packet_received)
# We'll also set up functions to inform the # We'll also set up functions to inform the
# user when the link is established or closed # user when the link is established or closed
link.link_established_callback(link_established) link.set_link_established_callback(link_established)
link.link_closed_callback(link_closed) link.set_link_closed_callback(link_closed)
# Everything is set up, so let's enter a loop # Everything is set up, so let's enter a loop
# for the user to interact with the example # for the user to interact with the example
@@ -181,8 +181,18 @@ def client_loop():
# If not, send the entered text over the link # If not, send the entered text over the link
if text != "": if text != "":
data = text.encode("utf-8") data = text.encode("utf-8")
RNS.Packet(server_link, data).send() if len(data) <= RNS.Link.MDU:
RNS.Packet(server_link, data).send()
else:
RNS.log(
"Cannot send this packet, the data size of "+
str(len(data))+" bytes exceeds the link packet MDU of "+
str(RNS.Link.MDU)+" bytes",
RNS.LOG_ERROR
)
except Exception as e: except Exception as e:
RNS.log("Error while sending data over the link: "+str(e))
should_quit = True should_quit = True
server_link.teardown() server_link.teardown()
+8 -4
View File
@@ -18,12 +18,13 @@ For more info, see [unsigned.io/projects/reticulum](https://unsigned.io/projects
## Notable Features ## Notable Features
- Coordination-less globally unique adressing and identification - Coordination-less globally unique adressing and identification
- Fully self-configuring multi-hop routing - Fully self-configuring multi-hop routing
- Asymmetric RSA encryption and signatures as basis for all communication - Asymmetric X25519 encryption and Ed25519 signatures as a basis for all communication
- Perfect Forward Secrecy on links with ephemereal Elliptic Curve Diffie-Hellman keys (on Curve25519) - Forward Secrecy with ephemereal Elliptic Curve Diffie-Hellman keys on Curve25519
- Reticulum uses the [Fernet](https://github.com/fernet/spec/blob/master/Spec.md) specification for encryption on links and to group destinations - Reticulum uses the [Fernet](https://github.com/fernet/spec/blob/master/Spec.md) specification for encryption
- AES-128 in CBC mode with PKCS7 padding - AES-128 in CBC mode with PKCS7 padding
- HMAC using SHA256 for authentication - HMAC using SHA256 for authentication
- IVs are generated through os.urandom() - IVs are generated through os.urandom()
- Keys are ephemeral and derived from an ECDH key exchange on Curve25519
- Unforgeable packet delivery confirmations - Unforgeable packet delivery confirmations
- A variety of supported interface types - A variety of supported interface types
- An intuitive and easy-to-use API - An intuitive and easy-to-use API
@@ -31,9 +32,12 @@ For more info, see [unsigned.io/projects/reticulum](https://unsigned.io/projects
- Reticulum can handle a few bytes of data or files of many gigabytes - Reticulum can handle a few bytes of data or files of many gigabytes
- Sequencing, transfer coordination and checksumming is automatic - Sequencing, transfer coordination and checksumming is automatic
- The API is very easy to use, and provides transfer progress - The API is very easy to use, and provides transfer progress
- Efficient link establishment
- Total bandwidth cost of setting up a link is 3 packets totalling 240 bytes
- Low cost of keeping links open at only 0.62 bits per second
## Where can Reticulum be used? ## Where can Reticulum be used?
On practically any hardware that can support at least a half-duplex channel with 1.000 bits per second throughput, and an MTU of 500 bytes. Data radios, modems, LoRa radios, serial lines, AX.25 TNCs, amateur radio digital modes, ad-hoc WiFi, free-space optical links and similar systems are all examples of the types of interfaces Reticulum was designed for. Over practically any medium that can support at least a half-duplex channel with 1.000 bits per second throughput, and an MTU of 500 bytes. Data radios, modems, LoRa radios, serial lines, AX.25 TNCs, amateur radio digital modes, ad-hoc WiFi, free-space optical links and similar systems are all examples of the types of interfaces Reticulum was designed for.
An open-source LoRa-based interface called [RNode](https://unsigned.io/projects/rnode/) has been designed specifically for use with Reticulum. It is possible to build yourself, or it can be purchased as a complete transceiver that just needs a USB connection to the host. An open-source LoRa-based interface called [RNode](https://unsigned.io/projects/rnode/) has been designed specifically for use with Reticulum. It is possible to build yourself, or it can be purchased as a complete transceiver that just needs a USB connection to the host.
+18 -26
View File
@@ -5,9 +5,6 @@ import RNS
from cryptography.fernet import Fernet from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.asymmetric import padding
class Callbacks: class Callbacks:
def __init__(self): def __init__(self):
@@ -31,9 +28,6 @@ class Destination:
:param \*aspects: Any non-zero number of string arguments. :param \*aspects: Any non-zero number of string arguments.
""" """
KEYSIZE = RNS.Identity.KEYSIZE;
PADDINGSIZE= RNS.Identity.PADDINGSIZE;
# Constants # Constants
SINGLE = 0x00 SINGLE = 0x00
GROUP = 0x01 GROUP = 0x01
@@ -139,8 +133,8 @@ class Destination:
def announce(self, app_data=None, path_response=False): def announce(self, app_data=None, path_response=False):
""" """
Creates an announce packet for this destination and broadcasts it on Creates an announce packet for this destination and broadcasts it on all
all interfaces. Application specific data can be added to the announce. relevant interfaces. Application specific data can be added to the announce.
:param app_data: *bytes* containing the app_data. :param app_data: *bytes* containing the app_data.
:param path_response: Internal flag used by :ref:`RNS.Transport<api-transport>`. Ignore. :param path_response: Internal flag used by :ref:`RNS.Transport<api-transport>`. Ignore.
@@ -162,10 +156,7 @@ class Destination:
signature = self.identity.sign(signed_data) signature = self.identity.sign(signed_data)
# TODO: Check if this could be optimised by only announce_data = self.identity.get_public_key()+random_hash+signature
# carrying the hash in the destination field, not
# also redundantly inside the signed blob as here
announce_data = self.hash+self.identity.get_public_key()+random_hash+signature
if app_data != None: if app_data != None:
announce_data += app_data announce_data += app_data
@@ -178,7 +169,7 @@ class Destination:
RNS.Packet(self, announce_data, RNS.Packet.ANNOUNCE, context = announce_context).send() RNS.Packet(self, announce_data, RNS.Packet.ANNOUNCE, context = announce_context).send()
def link_established_callback(self, callback): def set_link_established_callback(self, callback):
""" """
Registers a function to be called when a link has been established to Registers a function to be called when a link has been established to
this destination. this destination.
@@ -187,7 +178,7 @@ class Destination:
""" """
self.callbacks.link_established = callback self.callbacks.link_established = callback
def packet_callback(self, callback): def set_packet_callback(self, callback):
""" """
Registers a function to be called when a packet has been received by Registers a function to be called when a packet has been received by
this destination. this destination.
@@ -196,7 +187,7 @@ class Destination:
""" """
self.callbacks.packet = callback self.callbacks.packet = callback
def proof_requested_callback(self, callback): def set_proof_requested_callback(self, callback):
""" """
Registers a function to be called when a proof has been requested for Registers a function to be called when a proof has been requested for
a packet sent to this destination. Allows control over when and if a packet sent to this destination. Allows control over when and if
@@ -218,14 +209,15 @@ class Destination:
self.proof_strategy = proof_strategy self.proof_strategy = proof_strategy
def receive(self, packet): def receive(self, packet):
plaintext = self.decrypt(packet.data) if packet.packet_type == RNS.Packet.LINKREQUEST:
if plaintext != None: plaintext = packet.data
if packet.packet_type == RNS.Packet.LINKREQUEST: self.incoming_link_request(plaintext, packet)
self.incoming_link_request(plaintext, packet) else:
plaintext = self.decrypt(packet.data)
if packet.packet_type == RNS.Packet.DATA: if plaintext != None:
if self.callbacks.packet != None: if packet.packet_type == RNS.Packet.DATA:
self.callbacks.packet(plaintext, packet) if self.callbacks.packet != None:
self.callbacks.packet(plaintext, packet)
def incoming_link_request(self, data, packet): def incoming_link_request(self, data, packet):
link = RNS.Link.validate_request(self, data, packet) link = RNS.Link.validate_request(self, data, packet)
@@ -245,8 +237,8 @@ class Destination:
raise TypeError("A single destination holds keys through an Identity instance") raise TypeError("A single destination holds keys through an Identity instance")
if self.type == Destination.GROUP: if self.type == Destination.GROUP:
self.prv_bytes = Fernet.generate_key() self.prv_bytes = base64.urlsafe_b64decode(Fernet.generate_key())
self.prv = Fernet(self.prv_bytes) self.prv = Fernet(base64.urlsafe_b64encode(self.prv_bytes))
def get_private_key(self): def get_private_key(self):
@@ -278,7 +270,7 @@ class Destination:
if self.type == Destination.GROUP: if self.type == Destination.GROUP:
self.prv_bytes = key self.prv_bytes = key
self.prv = Fernet(self.prv_bytes) self.prv = Fernet(base64.urlsafe_b64encode(self.prv_bytes))
def load_public_key(self, key): def load_public_key(self, key):
if self.type != Destination.SINGLE: if self.type != Destination.SINGLE:
+170 -126
View File
@@ -4,14 +4,15 @@ import os
import RNS import RNS
import time import time
import atexit import atexit
import base64
from .vendor import umsgpack as umsgpack from .vendor import umsgpack as umsgpack
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.serialization import load_der_public_key from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey, Ed25519PublicKey
from cryptography.hazmat.primitives.serialization import load_der_private_key from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey, X25519PublicKey
from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives.asymmetric import padding from cryptography.fernet import Fernet
class Identity: class Identity:
""" """
@@ -19,26 +20,29 @@ class Identity:
for encryption, decryption, signatures and verification, and is the basis for encryption, decryption, signatures and verification, and is the basis
for all encrypted communication over Reticulum networks. for all encrypted communication over Reticulum networks.
:param public_only: Specifies whether this destination only holds a public key. :param create_keys: Specifies whether new encryption and signing keys should be generated.
""" """
KEYSIZE = 1024
CURVE = "Curve25519"
""" """
RSA key size in bits. The curve used for Elliptic Curve DH key exchanges
"""
KEYSIZE = 256*2
"""
X25519 key size in bits. A complete key is the concatenation of a 256 bit encryption key, and a 256 bit signing key.
""" """
DERKEYSIZE = KEYSIZE+272
# Non-configurable constants # Non-configurable constants
PADDINGSIZE = 336 # In bits AES_HMAC_OVERHEAD = 58 # In bytes
HASHLENGTH = 256 # In bits AES128_BLOCKSIZE = 16 # In bytes
SIGLENGTH = KEYSIZE HASHLENGTH = 256 # In bits
SIGLENGTH = KEYSIZE # In bits
ENCRYPT_CHUNKSIZE = (KEYSIZE-PADDINGSIZE)//8
DECRYPT_CHUNKSIZE = KEYSIZE//8
TRUNCATED_HASHLENGTH = 80 # In bits TRUNCATED_HASHLENGTH = 80 # In bits
""" """
Constant specifying the truncated hash length (in bits) used by Reticulum Constant specifying the truncated hash length (in bits) used by Reticulum
for addressable hashes. Non-configurable. for addressable hashes and other purposes. Non-configurable.
""" """
# Storage # Storage
@@ -46,7 +50,10 @@ class Identity:
@staticmethod @staticmethod
def remember(packet_hash, destination_hash, public_key, app_data = None): def remember(packet_hash, destination_hash, public_key, app_data = None):
Identity.known_destinations[destination_hash] = [time.time(), packet_hash, public_key, app_data] if len(public_key) != Identity.KEYSIZE//8:
raise TypeError("Can't remember "+RNS.prettyhexrep(destination_hash)+", the public key size of "+str(len(public_key))+" is not valid.", RNS.LOG_ERROR)
else:
Identity.known_destinations[destination_hash] = [time.time(), packet_hash, public_key, app_data]
@staticmethod @staticmethod
@@ -60,7 +67,7 @@ class Identity:
RNS.log("Searching for "+RNS.prettyhexrep(destination_hash)+"...", RNS.LOG_EXTREME) RNS.log("Searching for "+RNS.prettyhexrep(destination_hash)+"...", RNS.LOG_EXTREME)
if destination_hash in Identity.known_destinations: if destination_hash in Identity.known_destinations:
identity_data = Identity.known_destinations[destination_hash] identity_data = Identity.known_destinations[destination_hash]
identity = Identity(public_only=True) identity = Identity(create_keys=False)
identity.load_public_key(identity_data[2]) identity.load_public_key(identity_data[2])
identity.app_data = identity_data[3] identity.app_data = identity_data[3]
RNS.log("Found "+RNS.prettyhexrep(destination_hash)+" in known destinations", RNS.LOG_EXTREME) RNS.log("Found "+RNS.prettyhexrep(destination_hash)+" in known destinations", RNS.LOG_EXTREME)
@@ -145,19 +152,19 @@ class Identity:
if packet.packet_type == RNS.Packet.ANNOUNCE: if packet.packet_type == RNS.Packet.ANNOUNCE:
RNS.log("Validating announce from "+RNS.prettyhexrep(packet.destination_hash), RNS.LOG_DEBUG) RNS.log("Validating announce from "+RNS.prettyhexrep(packet.destination_hash), RNS.LOG_DEBUG)
destination_hash = packet.destination_hash destination_hash = packet.destination_hash
public_key = packet.data[10:Identity.DERKEYSIZE//8+10] public_key = packet.data[:Identity.KEYSIZE//8]
random_hash = packet.data[Identity.DERKEYSIZE//8+10:Identity.DERKEYSIZE//8+20] random_hash = packet.data[Identity.KEYSIZE//8:Identity.KEYSIZE//8+10]
signature = packet.data[Identity.DERKEYSIZE//8+20:Identity.DERKEYSIZE//8+20+Identity.KEYSIZE//8] signature = packet.data[Identity.KEYSIZE//8+10:Identity.KEYSIZE//8+10+Identity.KEYSIZE//8]
app_data = b"" app_data = b""
if len(packet.data) > Identity.DERKEYSIZE//8+20+Identity.KEYSIZE//8: if len(packet.data) > Identity.KEYSIZE//8+10+Identity.KEYSIZE//8:
app_data = packet.data[Identity.DERKEYSIZE//8+20+Identity.KEYSIZE//8:] app_data = packet.data[Identity.KEYSIZE//8+10+Identity.KEYSIZE//8:]
signed_data = destination_hash+public_key+random_hash+app_data signed_data = destination_hash+public_key+random_hash+app_data
if not len(packet.data) > Identity.DERKEYSIZE//8+20+Identity.KEYSIZE//8: if not len(packet.data) > Identity.KEYSIZE//8+10+Identity.KEYSIZE//8:
app_data = None app_data = None
announced_identity = Identity(public_only=True) announced_identity = Identity(create_keys=False)
announced_identity.load_public_key(public_key) announced_identity.load_public_key(public_key)
if announced_identity.pub != None and announced_identity.validate(signature, signed_data): if announced_identity.pub != None and announced_identity.validate(signature, signed_data):
@@ -184,40 +191,71 @@ class Identity:
:param path: The full path to the saved :ref:`RNS.Identity<api-identity>` data :param path: The full path to the saved :ref:`RNS.Identity<api-identity>` data
:returns: A :ref:`RNS.Identity<api-identity>` instance, or *None* if the loaded data was invalid. :returns: A :ref:`RNS.Identity<api-identity>` instance, or *None* if the loaded data was invalid.
""" """
identity = Identity(public_only=True) identity = Identity(create_keys=False)
if identity.load(path): if identity.load(path):
return identity return identity
else: else:
return None return None
@staticmethod
def from_bytes(prv_bytes):
"""
Create a new :ref:`RNS.Identity<api-identity>` instance from *bytes* of private key.
Can be used to load previously created and saved identities into Reticulum.
def __init__(self,public_only=False): :param prv_bytes: The *bytes* of private a saved private key. **HAZARD!** Never not use this to generate a new key by feeding random data in prv_bytes.
:returns: A :ref:`RNS.Identity<api-identity>` instance, or *None* if the *bytes* data was invalid.
"""
identity = Identity(create_keys=False)
if identity.load_private_key(prv_bytes):
return identity
else:
return None
def __init__(self,create_keys=True):
# Initialize keys to none # Initialize keys to none
self.prv = None self.prv = None
self.pub = None self.prv_bytes = None
self.prv_bytes = None self.sig_prv = None
self.pub_bytes = None self.sig_prv_bytes = None
self.hash = None
self.hexhash = None
if not public_only: self.pub = None
self.pub_bytes = None
self.sig_pub = None
self.sig_pub_bytes = None
self.hash = None
self.hexhash = None
if create_keys:
self.create_keys() self.create_keys()
def create_keys(self): def create_keys(self):
self.prv = rsa.generate_private_key( self.prv = X25519PrivateKey.generate()
public_exponent=65537, self.prv_bytes = self.prv.private_bytes(
key_size=Identity.KEYSIZE, encoding=serialization.Encoding.Raw,
backend=default_backend() format=serialization.PrivateFormat.Raw,
)
self.prv_bytes = self.prv.private_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption() encryption_algorithm=serialization.NoEncryption()
) )
self.pub = self.prv.public_key()
self.pub_bytes = self.pub.public_bytes( self.sig_prv = Ed25519PrivateKey.generate()
encoding=serialization.Encoding.DER, self.sig_prv_bytes = self.sig_prv.private_bytes(
format=serialization.PublicFormat.SubjectPublicKeyInfo encoding=serialization.Encoding.Raw,
format=serialization.PrivateFormat.Raw,
encryption_algorithm=serialization.NoEncryption()
)
self.pub = self.prv.public_key()
self.pub_bytes = self.pub.public_bytes(
encoding=serialization.Encoding.Raw,
format=serialization.PublicFormat.Raw
)
self.sig_pub = self.sig_prv.public_key()
self.sig_pub_bytes = self.sig_pub.public_bytes(
encoding=serialization.Encoding.Raw,
format=serialization.PublicFormat.Raw
) )
self.update_hashes() self.update_hashes()
@@ -228,13 +266,13 @@ class Identity:
""" """
:returns: The private key as *bytes* :returns: The private key as *bytes*
""" """
return self.prv_bytes return self.prv_bytes+self.sig_prv_bytes
def get_public_key(self): def get_public_key(self):
""" """
:returns: The public key as *bytes* :returns: The public key as *bytes*
""" """
return self.pub_bytes return self.pub_bytes+self.sig_pub_bytes
def load_private_key(self, prv_bytes): def load_private_key(self, prv_bytes):
""" """
@@ -244,42 +282,53 @@ class Identity:
:returns: True if the key was loaded, otherwise False. :returns: True if the key was loaded, otherwise False.
""" """
try: try:
self.prv_bytes = prv_bytes self.prv_bytes = prv_bytes[:Identity.KEYSIZE//8//2]
self.prv = serialization.load_der_private_key( self.prv = X25519PrivateKey.from_private_bytes(self.prv_bytes)
self.prv_bytes, self.sig_prv_bytes = prv_bytes[Identity.KEYSIZE//8//2:]
password=None, self.sig_prv = Ed25519PrivateKey.from_private_bytes(self.sig_prv_bytes)
backend=default_backend()
self.pub = self.prv.public_key()
self.pub_bytes = self.pub.public_bytes(
encoding=serialization.Encoding.Raw,
format=serialization.PublicFormat.Raw
) )
self.pub = self.prv.public_key()
self.pub_bytes = self.pub.public_bytes( self.sig_pub = self.sig_prv.public_key()
encoding=serialization.Encoding.DER, self.sig_pub_bytes = self.sig_pub.public_bytes(
format=serialization.PublicFormat.SubjectPublicKeyInfo encoding=serialization.Encoding.Raw,
format=serialization.PublicFormat.Raw
) )
self.update_hashes() self.update_hashes()
return True return True
except Exception as e: except Exception as e:
raise e
RNS.log("Failed to load identity key", RNS.LOG_ERROR) RNS.log("Failed to load identity key", RNS.LOG_ERROR)
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
return False return False
def load_public_key(self, key): def load_public_key(self, pub_bytes):
""" """
Load a public key into the instance. Load a public key into the instance.
:param prv_bytes: The public key as *bytes*. :param pub_bytes: The public key as *bytes*.
:returns: True if the key was loaded, otherwise False. :returns: True if the key was loaded, otherwise False.
""" """
try: try:
self.pub_bytes = key self.pub_bytes = pub_bytes[:Identity.KEYSIZE//8//2]
self.pub = load_der_public_key(self.pub_bytes, backend=default_backend()) self.sig_pub_bytes = pub_bytes[Identity.KEYSIZE//8//2:]
self.pub = X25519PublicKey.from_public_bytes(self.pub_bytes)
self.sig_pub = Ed25519PublicKey.from_public_bytes(self.sig_pub_bytes)
self.update_hashes() self.update_hashes()
except Exception as e: except Exception as e:
RNS.log("Error while loading public key, the contained exception was: "+str(e), RNS.LOG_ERROR) RNS.log("Error while loading public key, the contained exception was: "+str(e), RNS.LOG_ERROR)
def update_hashes(self): def update_hashes(self):
self.hash = Identity.truncated_hash(self.pub_bytes) self.hash = Identity.truncated_hash(self.get_public_key())
self.hexhash = self.hash.hex() self.hexhash = self.hash.hex()
def to_file(self, path): def to_file(self, path):
@@ -293,7 +342,7 @@ class Identity:
""" """
try: try:
with open(path, "wb") as key_file: with open(path, "wb") as key_file:
key_file.write(self.prv_bytes) key_file.write(self.get_public_key())
return True return True
return False return False
except Exception as e: except Exception as e:
@@ -310,71 +359,78 @@ class Identity:
RNS.log("Error while loading identity from "+str(path), RNS.LOG_ERROR) RNS.log("Error while loading identity from "+str(path), RNS.LOG_ERROR)
RNS.log("The contained exception was: "+str(e)) RNS.log("The contained exception was: "+str(e))
def get_salt(self):
return self.hash
def get_context(self):
return None
def encrypt(self, plaintext): def encrypt(self, plaintext):
""" """
Encrypts information for the identity. Encrypts information for the identity.
:param plaintext: The plaintext to be encrypted as *bytes*. :param plaintext: The plaintext to be encrypted as *bytes*.
:returns: Ciphertext as *bytes*. :returns: Ciphertext token as *bytes*.
:raises: *KeyError* if the instance does not hold a public key :raises: *KeyError* if the instance does not hold a public key.
""" """
if self.pub != None: if self.pub != None:
chunksize = Identity.ENCRYPT_CHUNKSIZE ephemeral_key = X25519PrivateKey.generate()
chunks = int(math.ceil(len(plaintext)/(float(chunksize)))) ephemeral_pub_bytes = ephemeral_key.public_key().public_bytes(
encoding=serialization.Encoding.Raw,
format=serialization.PublicFormat.Raw
)
ciphertext = b""; shared_key = ephemeral_key.exchange(self.pub)
for chunk in range(chunks): derived_key = derived_key = HKDF(
start = chunk*chunksize algorithm=hashes.SHA256(),
end = (chunk+1)*chunksize length=32,
if (chunk+1)*chunksize > len(plaintext): salt=self.get_salt(),
end = len(plaintext) info=self.get_context(),
).derive(shared_key)
ciphertext += self.pub.encrypt( fernet = Fernet(base64.urlsafe_b64encode(derived_key))
plaintext[start:end], ciphertext = base64.urlsafe_b64decode(fernet.encrypt(plaintext))
padding.OAEP( token = ephemeral_pub_bytes+ciphertext
mgf=padding.MGF1(algorithm=hashes.SHA1()),
algorithm=hashes.SHA1(), return token
label=None
)
)
return ciphertext
else: else:
raise KeyError("Encryption failed because identity does not hold a public key") raise KeyError("Encryption failed because identity does not hold a public key")
def decrypt(self, ciphertext): def decrypt(self, ciphertext_token):
""" """
Decrypts information for the identity. Decrypts information for the identity.
:param ciphertext: The ciphertext to be decrypted as *bytes*. :param ciphertext: The ciphertext to be decrypted as *bytes*.
:returns: Plaintext as *bytes*, or *None* if decryption fails. :returns: Plaintext as *bytes*, or *None* if decryption fails.
:raises: *KeyError* if the instance does not hold a private key :raises: *KeyError* if the instance does not hold a private key.
""" """
if self.prv != None: if self.prv != None:
plaintext = None if len(ciphertext_token) > Identity.KEYSIZE//8//2:
try: plaintext = None
chunksize = Identity.DECRYPT_CHUNKSIZE try:
chunks = int(math.ceil(len(ciphertext)/(float(chunksize)))) peer_pub_bytes = ciphertext_token[:Identity.KEYSIZE//8//2]
peer_pub = X25519PublicKey.from_public_bytes(peer_pub_bytes)
plaintext = b""; shared_key = self.prv.exchange(peer_pub)
for chunk in range(chunks): derived_key = derived_key = HKDF(
start = chunk*chunksize algorithm=hashes.SHA256(),
end = (chunk+1)*chunksize length=32,
if (chunk+1)*chunksize > len(ciphertext): salt=self.get_salt(),
end = len(ciphertext) info=self.get_context(),
).derive(shared_key)
plaintext += self.prv.decrypt( fernet = Fernet(base64.urlsafe_b64encode(derived_key))
ciphertext[start:end], ciphertext = ciphertext_token[Identity.KEYSIZE//8//2:]
padding.OAEP( plaintext = fernet.decrypt(base64.urlsafe_b64encode(ciphertext))
mgf=padding.MGF1(algorithm=hashes.SHA1()),
algorithm=hashes.SHA1(),
label=None
)
)
except:
RNS.log("Decryption by "+RNS.prettyhexrep(self.hash)+" failed", RNS.LOG_VERBOSE)
return plaintext; except Exception as e:
RNS.log("Decryption by "+RNS.prettyhexrep(self.hash)+" failed: "+str(e), RNS.LOG_DEBUG)
return plaintext;
else:
RNS.log("Decryption failed because the token size was invalid.", RNS.LOG_DEBUG)
return None
else: else:
raise KeyError("Decryption failed because identity does not hold a private key") raise KeyError("Decryption failed because identity does not hold a private key")
@@ -385,18 +441,14 @@ class Identity:
:param message: The message to be signed as *bytes*. :param message: The message to be signed as *bytes*.
:returns: Signature as *bytes*. :returns: Signature as *bytes*.
:raises: *KeyError* if the instance does not hold a private key :raises: *KeyError* if the instance does not hold a private key.
""" """
if self.prv != None: if self.sig_prv != None:
signature = self.prv.sign( try:
message, return self.sig_prv.sign(message)
padding.PSS( except Exception as e:
mgf=padding.MGF1(hashes.SHA256()), RNS.log("The identity "+str(self)+" could not sign the requested message. The contained exception was: "+str(e), RNS.LOG_ERROR)
salt_length=padding.PSS.MAX_LENGTH raise e
),
hashes.SHA256()
)
return signature
else: else:
raise KeyError("Signing failed because identity does not hold a private key") raise KeyError("Signing failed because identity does not hold a private key")
@@ -407,19 +459,11 @@ class Identity:
:param signature: The signature to be validated as *bytes*. :param signature: The signature to be validated as *bytes*.
:param message: The message to be validated as *bytes*. :param message: The message to be validated as *bytes*.
:returns: True if the signature is valid, otherwise False. :returns: True if the signature is valid, otherwise False.
:raises: *KeyError* if the instance does not hold a public key :raises: *KeyError* if the instance does not hold a public key.
""" """
if self.pub != None: if self.pub != None:
try: try:
self.pub.verify( self.sig_pub.verify(signature, message)
signature,
message,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
return True return True
except Exception as e: except Exception as e:
return False return False
+24 -31
View File
@@ -33,17 +33,15 @@ class Link:
:param peer_pub_bytes: Internal use, ignore this argument. :param peer_pub_bytes: Internal use, ignore this argument.
:param peer_sig_pub_bytes: Internal use, ignore this argument. :param peer_sig_pub_bytes: Internal use, ignore this argument.
""" """
CURVE = "Curve25519" CURVE = RNS.Identity.CURVE
""" """
The curve used for Elliptic Curve DH key exchanges The curve used for Elliptic Curve DH key exchanges
""" """
ECPUBSIZE = 32+32 ECPUBSIZE = 32+32
BLOCKSIZE = 16 KEYSIZE = 32
KEYSIZE = 32
AES_HMAC_OVERHEAD = 58 MDU = math.floor((RNS.Reticulum.MDU-RNS.Identity.AES_HMAC_OVERHEAD)/RNS.Identity.AES128_BLOCKSIZE)*RNS.Identity.AES128_BLOCKSIZE - 1
MDU = math.floor((RNS.Reticulum.MDU-AES_HMAC_OVERHEAD)/BLOCKSIZE)*BLOCKSIZE - 1
# TODO: This should not be hardcoded, # TODO: This should not be hardcoded,
# but calculated from something like # but calculated from something like
@@ -54,7 +52,7 @@ class Link:
""" """
TIMEOUT_FACTOR = 3 TIMEOUT_FACTOR = 3
STALE_GRACE = 2 STALE_GRACE = 2
KEEPALIVE = 180 KEEPALIVE = 360
""" """
Interval for sending keep-alive packets on established links in seconds. Interval for sending keep-alive packets on established links in seconds.
""" """
@@ -90,11 +88,6 @@ class Link:
link.last_inbound = time.time() link.last_inbound = time.time()
link.start_watchdog() link.start_watchdog()
# TODO: Why was link_established callback here? Seems weird
# to call this before RTT packet has been received
#if self.owner.callbacks.link_established != None:
# self.owner.callbacks.link_established(link)
RNS.log("Incoming link request "+str(link)+" accepted", RNS.LOG_VERBOSE) RNS.log("Incoming link request "+str(link)+" accepted", RNS.LOG_VERBOSE)
return link return link
@@ -135,14 +128,15 @@ class Link:
self.__encryption_disabled = False self.__encryption_disabled = False
if self.destination == None: if self.destination == None:
self.initiator = False self.initiator = False
self.prv = self.owner.identity.prv
self.sig_prv = self.owner.identity.sig_prv
else: else:
self.initiator = True self.initiator = True
self.prv = X25519PrivateKey.generate()
self.sig_prv = Ed25519PrivateKey.generate()
self.fernet = None self.fernet = None
self.prv = X25519PrivateKey.generate()
self.sig_prv = Ed25519PrivateKey.generate()
self.pub = self.prv.public_key() self.pub = self.prv.public_key()
self.pub_bytes = self.pub.public_bytes( self.pub_bytes = self.pub.public_bytes(
encoding=serialization.Encoding.Raw, encoding=serialization.Encoding.Raw,
@@ -162,10 +156,14 @@ class Link:
self.load_peer(peer_pub_bytes, peer_sig_pub_bytes) self.load_peer(peer_pub_bytes, peer_sig_pub_bytes)
if (self.initiator): if (self.initiator):
peer_pub_bytes = self.destination.identity.get_public_key()[:Link.ECPUBSIZE//2]
peer_sig_pub_bytes = self.destination.identity.get_public_key()[Link.ECPUBSIZE//2:Link.ECPUBSIZE]
self.request_data = self.pub_bytes+self.sig_pub_bytes self.request_data = self.pub_bytes+self.sig_pub_bytes
self.packet = RNS.Packet(destination, self.request_data, packet_type=RNS.Packet.LINKREQUEST) self.packet = RNS.Packet(destination, self.request_data, packet_type=RNS.Packet.LINKREQUEST)
self.packet.pack() self.packet.pack()
self.set_link_id(self.packet) self.set_link_id(self.packet)
self.load_peer(peer_pub_bytes, peer_sig_pub_bytes)
self.handshake()
RNS.Transport.register_link(self) RNS.Transport.register_link(self)
self.request_time = time.time() self.request_time = time.time()
self.start_watchdog() self.start_watchdog()
@@ -202,7 +200,7 @@ class Link:
signed_data = self.link_id+self.pub_bytes+self.sig_pub_bytes signed_data = self.link_id+self.pub_bytes+self.sig_pub_bytes
signature = self.owner.identity.sign(signed_data) signature = self.owner.identity.sign(signed_data)
proof_data = self.pub_bytes+self.sig_pub_bytes+signature proof_data = signature
proof = RNS.Packet(self, proof_data, packet_type=RNS.Packet.PROOF, context=RNS.Packet.LRPROOF) proof = RNS.Packet(self, proof_data, packet_type=RNS.Packet.PROOF, context=RNS.Packet.LRPROOF)
proof.send() proof.send()
self.had_outbound() self.had_outbound()
@@ -221,15 +219,11 @@ class Link:
self.had_outbound() self.had_outbound()
def validate_proof(self, packet): def validate_proof(self, packet):
if self.initiator and len(packet.data) == Link.ECPUBSIZE+RNS.Identity.KEYSIZE//8: if self.initiator and len(packet.data) == RNS.Identity.SIGLENGTH//8:
peer_pub_bytes = packet.data[:Link.ECPUBSIZE//2] signed_data = self.link_id+self.peer_pub_bytes+self.peer_sig_pub_bytes
peer_sig_pub_bytes = packet.data[Link.ECPUBSIZE//2:Link.ECPUBSIZE] signature = packet.data[:RNS.Identity.SIGLENGTH//8]
signed_data = self.link_id+peer_pub_bytes+peer_sig_pub_bytes
signature = packet.data[Link.ECPUBSIZE:RNS.Identity.KEYSIZE//8+Link.ECPUBSIZE]
if self.destination.identity.validate(signature, signed_data): if self.destination.identity.validate(signature, signed_data):
self.load_peer(peer_pub_bytes, peer_sig_pub_bytes)
self.handshake()
self.rtt = time.time() - self.request_time self.rtt = time.time() - self.request_time
self.attached_interface = packet.receiving_interface self.attached_interface = packet.receiving_interface
RNS.Transport.activate_link(self) RNS.Transport.activate_link(self)
@@ -265,8 +259,7 @@ class Link:
if self.owner.callbacks.link_established != None: if self.owner.callbacks.link_established != None:
self.owner.callbacks.link_established(self) self.owner.callbacks.link_established(self)
except Exception as e: except Exception as e:
RNS.log("Error occurred while processing RTT packet, tearing down link", RNS.LOG_ERROR) RNS.log("Error occurred while processing RTT packet, tearing down link. The contained exception was: "+str(e), RNS.LOG_ERROR)
traceback.print_exc()
self.teardown() self.teardown()
def get_salt(self): def get_salt(self):
@@ -537,13 +530,13 @@ class Link:
except Exception as e: except Exception as e:
return False return False
def link_established_callback(self, callback): def set_link_established_callback(self, callback):
self.callbacks.link_established = callback self.callbacks.link_established = callback
def link_closed_callback(self, callback): def set_link_closed_callback(self, callback):
self.callbacks.link_closed = callback self.callbacks.link_closed = callback
def packet_callback(self, callback): def set_packet_callback(self, callback):
""" """
Registers a function to be called when a packet has been Registers a function to be called when a packet has been
received over this link. received over this link.
@@ -552,7 +545,7 @@ class Link:
""" """
self.callbacks.packet = callback self.callbacks.packet = callback
def resource_callback(self, callback): def set_resource_callback(self, callback):
""" """
Registers a function to be called when a resource has been Registers a function to be called when a resource has been
advertised over this link. If the function returns *True* advertised over this link. If the function returns *True*
@@ -563,7 +556,7 @@ class Link:
""" """
self.callbacks.resource = callback self.callbacks.resource = callback
def resource_started_callback(self, callback): def set_resource_started_callback(self, callback):
""" """
Registers a function to be called when a resource has begun Registers a function to be called when a resource has begun
transferring over this link. transferring over this link.
@@ -572,7 +565,7 @@ class Link:
""" """
self.callbacks.resource_started = callback self.callbacks.resource_started = callback
def resource_concluded_callback(self, callback): def set_resource_concluded_callback(self, callback):
""" """
Registers a function to be called when a resource has concluded Registers a function to be called when a resource has concluded
transferring over this link. transferring over this link.
+30 -11
View File
@@ -6,8 +6,16 @@ import RNS
class Packet: class Packet:
""" """
The Packet class is used to create packet instances that can be The Packet class is used to create packet instances that can be sent
sent over a Reticulum network. over a Reticulum network. Packets to will automatically be encrypted if
they are adressed to a ``RNS.Destination.SINGLE`` destination,
``RNS.Destination.GROUP`` destination or a :ref:`RNS.Link<api-link>`.
For ``RNS.Destination.GROUP`` destinations, Reticulum will use the
pre-shared key configured for the destination.
For ``RNS.Destination.SINGLE`` destinations and :ref:`RNS.Link<api-link>`
destinations, reticulum will use ephemeral keys, and offers **Forward Secrecy**.
:param destination: A :ref:`RNS.Destination<api-destination>` instance to which the packet will be sent. :param destination: A :ref:`RNS.Destination<api-destination>` instance to which the packet will be sent.
:param data: The data payload to be included in the packet as *bytes*. :param data: The data payload to be included in the packet as *bytes*.
@@ -56,14 +64,21 @@ class Packet:
# This is used to calculate allowable # This is used to calculate allowable
# payload sizes # payload sizes
HEADER_MAXSIZE = 23 HEADER_MAXSIZE = RNS.Reticulum.HEADER_MAXSIZE
MDU = RNS.Reticulum.MDU MDU = RNS.Reticulum.MDU
# With an MTU of 500, the maximum RSA-encrypted # TODO: Update this
# amount of data we can send in a single packet # With an MTU of 500, the maximum of data we can
# is given by the below calculation; 258 bytes. # send in a single encrypted packet is given by
RSA_MDU = math.floor(MDU/RNS.Identity.DECRYPT_CHUNKSIZE)*RNS.Identity.ENCRYPT_CHUNKSIZE # the below calculation; 383 bytes.
PLAIN_MDU = MDU ENCRYPTED_MDU = math.floor((RNS.Reticulum.MDU-RNS.Identity.AES_HMAC_OVERHEAD-RNS.Identity.KEYSIZE//16)/RNS.Identity.AES128_BLOCKSIZE)*RNS.Identity.AES128_BLOCKSIZE - 1
"""
The maximum size of the payload data in a single encrypted packet
"""
PLAIN_MDU = MDU
"""
The maximum size of the payload data in a single unencrypted packet
"""
# TODO: This should be calculated # TODO: This should be calculated
# more intelligently # more intelligently
@@ -128,6 +143,9 @@ class Packet:
if self.packet_type == Packet.ANNOUNCE: if self.packet_type == Packet.ANNOUNCE:
# Announce packets are not encrypted # Announce packets are not encrypted
self.ciphertext = self.data self.ciphertext = self.data
elif self.packet_type == Packet.LINKREQUEST:
# Link request packets are not encrypted
self.ciphertext = self.data
elif self.packet_type == Packet.PROOF and self.context == Packet.RESOURCE_PRF: elif self.packet_type == Packet.PROOF and self.context == Packet.RESOURCE_PRF:
# Resource proofs are not encrypted # Resource proofs are not encrypted
self.ciphertext = self.data self.ciphertext = self.data
@@ -171,6 +189,7 @@ class Packet:
self.packed = True self.packed = True
self.update_hash() self.update_hash()
def unpack(self): def unpack(self):
self.flags = self.raw[0] self.flags = self.raw[0]
self.hops = self.raw[1] self.hops = self.raw[1]
@@ -406,7 +425,7 @@ class PacketReceipt:
else: else:
return False return False
def rtt(self): def get_rtt(self):
""" """
:returns: The round-trip-time in seconds :returns: The round-trip-time in seconds
""" """
@@ -439,7 +458,7 @@ class PacketReceipt:
""" """
self.timeout = float(timeout) self.timeout = float(timeout)
def delivery_callback(self, callback): def set_delivery_callback(self, callback):
""" """
Sets a function that gets called if a successfull delivery has been proven. Sets a function that gets called if a successfull delivery has been proven.
@@ -449,7 +468,7 @@ class PacketReceipt:
# Set a function that gets called if the # Set a function that gets called if the
# delivery times out # delivery times out
def timeout_callback(self, callback): def set_timeout_callback(self, callback):
""" """
Sets a function that gets called if the delivery times out. Sets a function that gets called if the delivery times out.
+2 -5
View File
@@ -17,7 +17,6 @@ class Resource:
:param link: The :ref:`RNS.Link<api-link>` instance on which to transfer the data. :param link: The :ref:`RNS.Link<api-link>` instance on which to transfer the data.
:param advertise: Whether to automatically advertise the resource. Can be *True* or *False*. :param advertise: Whether to automatically advertise the resource. Can be *True* or *False*.
:param auto_compress: Whether to auto-compress the resource. Can be *True* or *False*. :param auto_compress: Whether to auto-compress the resource. Can be *True* or *False*.
:param auto_compress: Whether the resource must be compressed. Can be *True* or *False*. Used for debugging, will disappear in the future.
:param callback: A *callable* with the signature *callback(resource)*. Will be called when the resource transfer concludes. :param callback: A *callable* with the signature *callback(resource)*. Will be called when the resource transfer concludes.
:param progress_callback: A *callable* with the signature *callback(resource)*. Will be called whenever the resource transfer progress is updated. :param progress_callback: A *callable* with the signature *callback(resource)*. Will be called whenever the resource transfer progress is updated.
:param segment_index: Internal use, ignore. :param segment_index: Internal use, ignore.
@@ -134,7 +133,7 @@ class Resource:
# Create a resource for transmission to a remote destination # Create a resource for transmission to a remote destination
# The data passed can be either a bytes-array or a file opened # The data passed can be either a bytes-array or a file opened
# in binary read mode. # in binary read mode.
def __init__(self, data, link, advertise=True, auto_compress=True, must_compress=False, callback=None, progress_callback=None, segment_index = 1, original_hash = None): def __init__(self, data, link, advertise=True, auto_compress=True, callback=None, progress_callback=None, segment_index = 1, original_hash = None):
data_size = None data_size = None
resource_data = None resource_data = None
if hasattr(data, "read"): if hasattr(data, "read"):
@@ -198,7 +197,7 @@ class Resource:
self.uncompressed_data = data self.uncompressed_data = data
compression_began = time.time() compression_began = time.time()
if must_compress or (auto_compress and len(self.uncompressed_data) < Resource.AUTO_COMPRESS_MAX_SIZE): if (auto_compress and len(self.uncompressed_data) < Resource.AUTO_COMPRESS_MAX_SIZE):
RNS.log("Compressing resource data...", RNS.LOG_DEBUG) RNS.log("Compressing resource data...", RNS.LOG_DEBUG)
self.compressed_data = bz2.compress(self.uncompressed_data) self.compressed_data = bz2.compress(self.uncompressed_data)
RNS.log("Compression completed in "+str(round(time.time()-compression_began, 3))+" seconds", RNS.LOG_DEBUG) RNS.log("Compression completed in "+str(round(time.time()-compression_began, 3))+" seconds", RNS.LOG_DEBUG)
@@ -748,8 +747,6 @@ class Resource:
:returns: The current progress of the resource transfer as a *float* between 0.0 and 1.0. :returns: The current progress of the resource transfer as a *float* between 0.0 and 1.0.
""" """
if self.initiator: if self.initiator:
# TODO: Remove
# progress = self.sent_parts / len(self.parts)
self.processed_parts = (self.segment_index-1)*math.ceil(Resource.MAX_EFFICIENT_SIZE/Resource.SDU) self.processed_parts = (self.segment_index-1)*math.ceil(Resource.MAX_EFFICIENT_SIZE/Resource.SDU)
self.processed_parts += self.sent_parts self.processed_parts += self.sent_parts
self.progress_total_parts = float(self.grand_total_parts) self.progress_total_parts = float(self.grand_total_parts)
+2 -4
View File
@@ -22,8 +22,6 @@ class Transport:
APP_NAME = "rnstransport" APP_NAME = "rnstransport"
# TODO: Document the addition of random windows
# and max local rebroadcasts.
PATHFINDER_M = 18 # Max hops PATHFINDER_M = 18 # Max hops
PATHFINDER_C = 2.0 # Decay constant PATHFINDER_C = 2.0 # Decay constant
PATHFINDER_R = 1 # Retransmit retries PATHFINDER_R = 1 # Retransmit retries
@@ -108,7 +106,7 @@ class Transport:
# Create transport-specific destinations # Create transport-specific destinations
Transport.path_request_destination = RNS.Destination(None, RNS.Destination.IN, RNS.Destination.PLAIN, Transport.APP_NAME, "path", "request") Transport.path_request_destination = RNS.Destination(None, RNS.Destination.IN, RNS.Destination.PLAIN, Transport.APP_NAME, "path", "request")
Transport.path_request_destination.packet_callback(Transport.path_request_handler) Transport.path_request_destination.set_packet_callback(Transport.path_request_handler)
Transport.control_destinations.append(Transport.path_request_destination) Transport.control_destinations.append(Transport.path_request_destination)
Transport.control_hashes.append(Transport.path_request_destination.hash) Transport.control_hashes.append(Transport.path_request_destination.hash)
@@ -652,7 +650,7 @@ class Transport:
# First, check that the announce is not for a destination # First, check that the announce is not for a destination
# local to this system, and that hops are less than the max # local to this system, and that hops are less than the max
if (not any(packet.destination_hash == d.hash for d in Transport.destinations) and packet.hops < Transport.PATHFINDER_M+1): if (not any(packet.destination_hash == d.hash for d in Transport.destinations) and packet.hops < Transport.PATHFINDER_M+1):
random_blob = packet.data[RNS.Identity.DERKEYSIZE//8+10:RNS.Identity.DERKEYSIZE//8+20] random_blob = packet.data[RNS.Identity.KEYSIZE//8+10:RNS.Identity.KEYSIZE//8+20]
random_blobs = [] random_blobs = []
if packet.destination_hash in Transport.destination_table: if packet.destination_hash in Transport.destination_table:
random_blobs = Transport.destination_table[packet.destination_hash][4] random_blobs = Transport.destination_table[packet.destination_hash][4]
Binary file not shown.
+1 -1
View File
@@ -1,4 +1,4 @@
# Sphinx build info version 1 # Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: 010a10c5bc670583cef4151858e38839 config: 205a0b937612ce08d1a58b1cbb471256
tags: 645f666f9bcd5a90fca523b33c5a78b7 tags: 645f666f9bcd5a90fca523b33c5a78b7
Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

@@ -1,7 +1,6 @@
******************** ********************
Getting Started Fast Getting Started Fast
******************** ********************
What do we want to do? Something! When do we want to do it? Right now! Let's go.
The best way to get started with the Reticulum Network Stack depends on what The best way to get started with the Reticulum Network Stack depends on what
you want to do. This guide will outline sensible starting paths for different you want to do. This guide will outline sensible starting paths for different
@@ -23,7 +22,7 @@ in the development for the messaging and information-sharing protocol
Develop a Program with Reticulum Develop a Program with Reticulum
=========================================== ===========================================
If you want to develop programs that use Reticulum, the easiest way to get If you want to develop programs that use Reticulum, the easiest way to get
started is to install Reticulum via pip: started is to install the latest release of Reticulum via pip:
.. code:: .. code::
+2 -2
View File
@@ -10,9 +10,9 @@ the development of Reticulum itself.
whatis whatis
gettingstartedfast gettingstartedfast
examples
reference
understanding understanding
reference
examples
Indices and Tables Indices and Tables
+140 -93
View File
@@ -157,12 +157,16 @@ destinations. Reticulum uses three different basic destination types, and one sp
Destination Naming Destination Naming
^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
Destinations are created and named in an easy to understand dotted notation of *aspects* , and Destinations are created and named in an easy to understand dotted notation of *aspects*, and
represented on the network as a hash of this value. The hash is a SHA-256 truncated to 80 bits. The represented on the network as a hash of this value. The hash is a SHA-256 truncated to 80 bits. The
top level aspect should always be a unique identifier for the application using the destination. top level aspect should always be a unique identifier for the application using the destination.
The next levels of aspects can be defined in any way by the creator of the application. For example, The next levels of aspects can be defined in any way by the creator of the application.
a destination for a environmental monitoring application could be made up of the application name, a
device type and measurement type, like this: Aspects can be as long and as plentiful as required, and a resulting long destination name will not
impact efficiency, as names are always represented as truncated SHA-256 hashes on the network.
As an example, a destination for a environmental monitoring application could be made up of the
application name, a device type and measurement type, like this:
.. code-block:: text .. code-block:: text
@@ -201,9 +205,8 @@ To recap, the different destination types should be used in the following situat
* **Single** * **Single**
When private communication between two endpoints is needed. Supports multiple hops. When private communication between two endpoints is needed. Supports multiple hops.
* **Group** * **Group**
When private communication between two or more endpoints is needed. More efficient in When private communication between two or more endpoints is needed. Supports multiple hops
data usage than *single* destinations. Supports multiple hops indirectly, but must first be indirectly, but must first be established through a *single* destination.
established through a *single* destination.
* **Plain** * **Plain**
When plain-text communication is desirable, for example when broadcasting information. When plain-text communication is desirable, for example when broadcasting information.
@@ -214,9 +217,9 @@ an unknown public key from the network, as all participating nodes serve as a di
of public keys. of public keys.
Note that public key information can be shared and verified in many other ways than using the Note that public key information can be shared and verified in many other ways than using the
built-in methodology, and that it is therefore not required to use the announce/request functionality. built-in *announce* functionality, and that it is therefore not required to use the announce/request
It is by far the easiest though, and should definitely be used if there is not a good reason for functionality to obtain public keys. It is by far the easiest though, and should definitely be used
doing it differently. if there is not a good reason for doing it differently.
.. _understanding-keyannouncements: .. _understanding-keyannouncements:
@@ -235,7 +238,7 @@ contain the following information:
* The announcers public key * The announcers public key
* Application specific data, in this case the users nickname and availability status * Application specific data, in this case the users nickname and availability status
* A random blob, making each new announce unique * A random blob, making each new announce unique
* A signature of the above information, verifying authenticity * An Ed25519 signature of the above information, verifying authenticity
With this information, any Reticulum node that receives it will be able to reconstruct an outgoing With this information, any Reticulum node that receives it will be able to reconstruct an outgoing
destination to securely communicate with that destination. You might have noticed that there is one destination to securely communicate with that destination. You might have noticed that there is one
@@ -244,8 +247,9 @@ the aspect names of the destination. These are intentionally left out to save ba
will be implicit in almost all cases. If a destination name is not entirely implicit, information can be will be implicit in almost all cases. If a destination name is not entirely implicit, information can be
included in the application specific data part that will allow the receiver to infer the naming. included in the application specific data part that will allow the receiver to infer the naming.
It is important to note that announcements will be forwarded throughout the network according to a It is important to note that announces will be forwarded throughout the network according to a
certain pattern. This will be detailed later. certain pattern. This will be detailed in the section
:ref:`The Announce Mechanism in Detail<understanding-announce>`.
Seeing how *single* destinations are always tied to a private/public key pair leads us to the next topic. Seeing how *single* destinations are always tied to a private/public key pair leads us to the next topic.
@@ -268,8 +272,8 @@ the identity first, and then link it to created destinations.
Building upon the simple messenger example, we could use an identity to represent the user of the Building upon the simple messenger example, we could use an identity to represent the user of the
application. Destinations created will then be linked to this identity to allow communication to application. Destinations created will then be linked to this identity to allow communication to
reach the user. In such a case it is of great importance to store the users identity securely and reach the user. In all cases it is of great importance to store the private keys associated with any
privately. Reticulum Identity securely and privately.
.. _understanding-gettingfurther: .. _understanding-gettingfurther:
@@ -279,8 +283,9 @@ Getting Further
The above functions and principles form the core of Reticulum, and would suffice to create The above functions and principles form the core of Reticulum, and would suffice to create
functional networked applications in local clusters, for example over radio links where all interested functional networked applications in local clusters, for example over radio links where all interested
nodes can directly hear each other. But to be truly useful, we need a way to direct traffic over multiple nodes can directly hear each other. But to be truly useful, we need a way to direct traffic over multiple
hops in the network. In the next sections, two concepts that allow this will be introduced, *paths* and hops in the network.
*links*.
In the following sections, two concepts that allow this will be introduced, *paths* and *links*.
.. _understanding-transport: .. _understanding-transport:
@@ -298,70 +303,28 @@ useable over bandwidth-limited, high-latency links.
To overcome such challenges, Reticulums *Transport* system uses public-key cryptography to To overcome such challenges, Reticulums *Transport* system uses public-key cryptography to
implement the concept of *paths* that allow discovery of how to get information to a certain implement the concept of *paths* that allow discovery of how to get information to a certain
destination, and *resources* that help make reliable data transfer more efficient. destination. It is important to note that no single node in a Reticulum network knows the complete
path to a destination. Every Transport node participating in a Reticulum network will only
know what the most direct way to get a packet one hop closer to it's destination is.
.. _understanding-paths: .. _understanding-announce:
Reaching the Destination The Announce Mechanism in Detail
------------------------ --------------------------------
In networks with changing topology and trustless connectivity, nodes need a way to establish When an *announce* is transmitted by a node, it will be forwarded by any node receiving it, but
*verified connectivity* with each other. Since the network is assumed to be trustless, Reticulum according to some specific rules:
must provide a way to guarantee that the peer you are communicating with is actually who you
expect. To do this, the following process is employed:
* | First, the node that wishes to establish connectivity will send out a special packet, that * | If this exact announce has already been received before, ignore it.
traverses the network and locates the desired destination. Along the way, the nodes that
forward the packet will take note of this *link request*.
* | Second, if the destination accepts the *link request* , it will send back a packet that proves the * | If not, record into a table which node the announce was received from, and how many times in
authenticity of its identity (and the receipt of the link request) to the initiating node. All
nodes that initially forwarded the packet will also be able to verify this proof, and thus
accept the validity of the *link* throughout the network.
* | When the validity of the *link* has been accepted by forwarding nodes, these nodes will
remember the *link* , and it can subsequently be used by referring to a hash representing it.
* | As a part of the *link request* , a Diffie-Hellman key exchange takes place, that sets up an
efficient symmetrically encrypted tunnel between the two nodes, using elliptic curve
cryptography. As such, this mode of communication is preferred, even for situations when
nodes can directly communicate, when the amount of data to be exchanged numbers in the
tens of packets.
* | When a *link* has been set up, it automatically provides message receipt functionality, so the
sending node can obtain verified confirmation that the information reached the intended
recipient.
In a moment, we will discuss the specifics of how this methodology is implemented, but lets first
recap what purposes this serves. We first ensure that the node answering our request is actually the
one we want to communicate with, and not a malicious actor pretending to be so. At the same time
we establish an efficient encrypted channel. The setup of this is relatively cheap in terms of
bandwidth, so it can be used just for a short exchange, and then recreated as needed, which will also
rotate encryption keys, but the link can also be kept alive for longer periods of time, if this is
more suitable to the application. The amount of bandwidth used on keeping a link open is practically
negligible. The procedure also inserts the *link id* , a hash calculated from the link request packet,
into the memory of forwarding nodes, which means that the communicating nodes can thereafter reach each
other simply by referring to this *link id*.
Step 1: Pathfinding
^^^^^^^^^^^^^^^^^^^
The pathfinding method builds on the *announce* functionality discussed earlier. When an announce
is sent out by a node, it will be forwarded by any node receiving it, but according to some specific
rules:
* | If this announce has already been received before, ignore it.
* | Record into a table which node the announce was received from, and how many times in
total it has been retransmitted to get here. total it has been retransmitted to get here.
* | If the announce has been retransmitted *m+1* times, it will not be forwarded. By default, *m* is * | If the announce has been retransmitted *m+1* times, it will not be forwarded. By default, *m* is
set to 18. set to 18.
* | The announce will be assigned a delay *d* = c\ :sup:`h` seconds, where *c* is a decay constant, by * | The announce will be assigned a delay *d* = c\ :sup:`h` seconds, where *c* is a decay constant, and *h* is the amount of times this packet has already been forwarded.
default 2, and *h* is the amount of times this packet has already been forwarded.
* | The packet will be given a priority *p = 1/d*. * | The packet will be given a priority *p = 1/d*.
@@ -370,10 +333,11 @@ rules:
not utilized by other traffic, the announce will be forwarded. not utilized by other traffic, the announce will be forwarded.
* | If no other nodes are heard retransmitting the announce with a greater hop count than when * | If no other nodes are heard retransmitting the announce with a greater hop count than when
it left this node, transmitting it will be retried *r* times. By default, *r* is set to 2. Retries follow it left this node, transmitting it will be retried *r* times. By default, *r* is set to 1. Retries
same rules as above, with the exception that it must wait for at least *d* = c\ :sup:`h+1` + t seconds, ie., follow same rules as above, with the exception that it must wait for at least *d* = c\ :sup:`h+1` +
the amount of time it would take the next node to retransmit the packet. By default, *t* is set to t + rand(0, rw) seconds. This amount of time is equal to the amount of time it would take the next
10. node to retransmit the packet, plus a random window. By default, *t* is set to 10 seconds, and the
random window *rw* is set to 10 seconds.
* | If a newer announce from the same destination arrives, while an identical one is already in * | If a newer announce from the same destination arrives, while an identical one is already in
the queue, the newest announce is discarded. If the newest announce contains different the queue, the newest announce is discarded. If the newest announce contains different
@@ -392,14 +356,95 @@ distance of *Lavg =* 15 kilometers, an announce will be able to propagate outwar
kilometers in 34 minutes, and a *maximum announce radius* of 270 kilometers in approximately 3 kilometers in 34 minutes, and a *maximum announce radius* of 270 kilometers in approximately 3
days. days.
Step 2: Link Establishment .. _understanding-paths:
^^^^^^^^^^^^^^^^^^^^^^^^^^
After seeing how the conditions for finding a path through the network are created, we will now Reaching the Destination
explore how two nodes can establish reliable communications over multiple hops. The *link* in ------------------------
Reticulum terminology should not be viewed as a direct node-to-node link on the physical layer, but
as an abstract channel, that can be open for any amount of time, and can span an arbitrary number In networks with changing topology and trustless connectivity, nodes need a way to establish
of hops, where information will be exchanged between two nodes. *verified connectivity* with each other. Since the network is assumed to be trustless, Reticulum
must provide a way to guarantee that the peer you are communicating with is actually who you
expect. Reticulum offers two ways to do this.
For exchanges of small amounts of information, Reticulum offers the *Packet* API, which works exactly like you would expect - on a per packet level. The following process is employed when sending a packet:
* | A packet is always created with an associated destination and some payload data. When the packet is sent
to a *single* destination type, Reticulum will automatically create an ephemeral encryption key, perform
an ECDH key exchange with the destinations public key, and encrypt the information.
* | It is important to note that this key exchange does not require any network traffic. The sender already
knows the public key of the destination from an earlier received *announce*, and can thus perform the ECDH
key exchange locally, before sending the packet.
* | The public part of the newly generated ephemeral key-pair is included with the encrypted token, and sent
along with the encrypted payload data in the packet.
* | When the destination receives the packet, it can itself perform an ECDH key exchange and decrypt the
packet.
* | A new ephemeral key is used for every packet sent in this way, and forward secrecy is guaranteed on a
per packet level.
* | Once the packet has been received and decrypted by the addressed destination, that destination can opt
to *prove* its receipt of the packet. It does this by calculating the SHA-256 hash of the received packet,
and signing this hash with it's Ed25519 signing key. Transport nodes in the network can then direct this
*proof* back to the packets origin, where the signature can be verified against the destinations known
public signing key.
* | In case the packet is addressed to a *group* destination type, the packet will be encrypted with the
pre-shared AES-128 key associated with the destination. In case the packet is addressed to a *plain*
destination type, the payload data will not be encrypted. Neither of these two destination types offer
forward secrecy. In general, it is recommended to always use the *single* destination type, unless it is
strictly necessary to use one of the others.
For exchanges of larger amounts of data, or when longer sessions of bidirectional communication is desired, Reticulum offers the *Link* API. To establish a *link*, the following process is employed:
* | First, the node that wishes to establish a link will send out a special packet, that
traverses the network and locates the desired destination. Along the way, the nodes that
forward the packet will take note of this *link request*.
* | Second, if the destination accepts the *link request* , it will send back a packet that proves the
authenticity of its identity (and the receipt of the link request) to the initiating node. All
nodes that initially forwarded the packet will also be able to verify this proof, and thus
accept the validity of the *link* throughout the network.
* | When the validity of the *link* has been accepted by forwarding nodes, these nodes will
remember the *link* , and it can subsequently be used by referring to a hash representing it.
* | As a part of the *link request* , a Diffie-Hellman key exchange takes place, that sets up an
efficiently encrypted tunnel between the two nodes, using elliptic curve cryptography. As such,
this mode of communication is preferred, even for situations when nodes can directly communicate,
when the amount of data to be exchanged numbers in the tens of packets.
* | When a *link* has been set up, it automatically provides message receipt functionality, through
the same *proof* mechanism discussed before, so the sending node can obtain verified confirmation
that the information reached the intended recipient.
In a moment, we will discuss the details of how this methodology is implemented, but lets first
recap what purposes this methodology serves. We first ensure that the node answering our request
is actually the one we want to communicate with, and not a malicious actor pretending to be so.
At the same time we establish an efficient encrypted channel. The setup of this is relatively cheap in
terms of bandwidth, so it can be used just for a short exchange, and then recreated as needed, which will
also rotate encryption keys. The link can also be kept alive for longer periods of time, if this is
more suitable to the application. The procedure also inserts the *link id* , a hash calculated from the link request packet, into the memory of forwarding nodes, which means that the communicating nodes can thereafter reach each other simply by referring to this *link id*.
The combined bandwidth cost of setting up a link is 3 packets totalling 240 bytes (more info in the
:ref:`Binary Packet Format<understanding-packetformat>` section). The amount of bandwidth used on keeping
a link open is practically negligible, at 0.62 bits per second. Even on a slow 1200 bits per second packet
radio channel, 100 concurrent links will still leave 95% channel capacity for actual data.
Link Establishment in Detail
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
After exploring the basics of the announce mechanism, finding a path through the network, and an overview
of the link establishment procedure, this section will go into greater detail about the Reticulum link
establishment process.
The *link* in Reticulum terminology should not be viewed as a direct node-to-node link on the
physical layer, but as an abstract channel, that can be open for any amount of time, and can span
an arbitrary number of hops, where information will be exchanged between two nodes.
* | When a node in the network wants to establish verified connectivity with another node, it * | When a node in the network wants to establish verified connectivity with another node, it
@@ -412,25 +457,25 @@ of hops, where information will be exchanged between two nodes.
considered as single public key for simplicity in this explanation.* considered as single public key for simplicity in this explanation.*
* | The *link request* is addressed to the destination hash of the desired destination, and * | The *link request* is addressed to the destination hash of the desired destination, and
contains the following data: The newly generated X25519 public key *LKi*. The contents contains the following data: The newly generated X25519 public key *LKi*.
are encrypted with the RSA public key of the destination and tramsitted over the network.
* | The broadcasted packet will be directed through the network according to the rules laid out * | The broadcasted packet will be directed through the network according to the rules laid out
previously. previously.
* | Any node that forwards the link request will store a *link id* in its *link table* , along with the * | Any node that forwards the link request will store a *link id* in its *link table* , along with the
amount of hops the packet had taken when received. The link id is a hash of the entire link amount of hops the packet had taken when received. The link id is a hash of the entire link
request packet. If the path is not *proven* within some set amount of time, the entry will be request packet. If the link request packet is not *proven* by the addressed destination within some
dropped from the *link table* again. set amount of time, the entry will be dropped from the *link table* again.
* | When the destination receives the link request packet, it will decrypt it and decide whether to * | When the destination receives the link request packet, it will decide whether to accept the request.
accept the request. If it is accepted, the destination will also generate a new X25519 private/public If it is accepted, the destination will also generate a new X25519 private/public key pair, and
key pair, and perform a Diffie Hellman Key Exchange, deriving a new symmetric key that will be used perform a Diffie Hellman Key Exchange, deriving a new symmetric key that will be used to encrypt the
to encrypt the channel, once it has been established. channel, once it has been established.
* | A *link proof* packet is now constructed and transmitted over the network. This packet is * | A *link proof* packet is now constructed and transmitted over the network. This packet is
addressed to the *link id* of the *link*. It contains the following data: The newly generated X25519 addressed to the *link id* of the *link*. It contains the following data: The newly generated X25519
public key *LKr* and an RSA-1024 signature of the *link id* and *LKr*. public key *LKr* and an Ed25519 signature of the *link id* and *LKr* made by the signing key of
the addressed destination.
* | By verifying this *link proof* packet, all nodes that originally transported the *link request* * | By verifying this *link proof* packet, all nodes that originally transported the *link request*
packet to the destination from the originator can now verify that the intended destination received packet to the destination from the originator can now verify that the intended destination received
@@ -556,6 +601,8 @@ the light of Reticulums goal of equal access, doing so would need to be the subj
investigation of the consequences first. investigation of the consequences first.
.. _understanding-packetformat:
Binary Packet Format Binary Packet Format
-------------------- --------------------
@@ -651,8 +698,8 @@ Binary Packet Format
wire size including all fields. wire size including all fields.
- Path Request : 33 bytes - Path Request : 33 bytes
- Announce : 323 bytes - Announce : 151 bytes
- Link Request : 141 bytes - Link Request : 77 bytes
- Link Proof : 205 bytes - Link Proof : 77 bytes
- Link RTT packet : 86 bytes - Link RTT packet : 86 bytes
- Link keepalive : 14 bytes - Link keepalive : 14 bytes
+12 -4
View File
@@ -25,11 +25,11 @@ What does Reticulum Offer?
* Fully self-configuring multi-hop routing * Fully self-configuring multi-hop routing
* Asymmetric RSA encryption and signatures as basis for all communication * Asymmetric X25519 encryption and Ed25519 signatures as a basis for all communication
* Perfect Forward Secrecy on links with ephemereal Elliptic Curve Diffie-Hellman keys (on Curve25519) * Forward Secrecy with ephemereal Elliptic Curve Diffie-Hellman keys on Curve25519
* Reticulum uses the Fernet specification for encryption on links and to group destinations * Reticulum uses the `Fernet <https://github.com/fernet/spec/blob/master/Spec.md>`_ specification for encryption
* AES-128 in CBC mode with PKCS7 padding * AES-128 in CBC mode with PKCS7 padding
@@ -37,6 +37,8 @@ What does Reticulum Offer?
* IVs are generated through os.urandom() * IVs are generated through os.urandom()
* Keys are ephemeral and derived from an ECDH key exchange on Curve25519
* Unforgeable packet delivery confirmations * Unforgeable packet delivery confirmations
* A variety of supported interface types * A variety of supported interface types
@@ -51,10 +53,16 @@ What does Reticulum Offer?
* The API is very easy to use, and provides transfer progress * The API is very easy to use, and provides transfer progress
* Efficient link establishment
* Total bandwidth cost of setting up a link is only 3 packets, totalling 240 bytes
* Low cost of keeping links open at only 0.62 bits per second
Where can Reticulum be Used? Where can Reticulum be Used?
============================ ============================
On practically any hardware that can support at least a half-duplex channel Over practically any medium that can support at least a half-duplex channel
with 1.000 bits per second throughput, and an MTU of 500 bytes. Data radios, with 1.000 bits per second throughput, and an MTU of 500 bytes. Data radios,
modems, LoRa radios, serial lines, AX.25 TNCs, amateur radio digital modes, modems, LoRa radios, serial lines, AX.25 TNCs, amateur radio digital modes,
ad-hoc WiFi, free-space optical links and similar systems are all examples ad-hoc WiFi, free-space optical links and similar systems are all examples
+1 -1
View File
@@ -1,6 +1,6 @@
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
VERSION: '0.2.0 beta', VERSION: '0.2.1 beta',
LANGUAGE: 'None', LANGUAGE: 'None',
COLLAPSE_INDEX: false, COLLAPSE_INDEX: false,
BUILDER: 'html', BUILDER: 'html',
+37 -37
View File
@@ -5,7 +5,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Examples &#8212; Reticulum Network Stack 0.2.0 beta documentation</title> <title>Examples &#8212; Reticulum Network Stack 0.2.1 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" /> <link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -16,8 +16,7 @@
<link rel="index" title="Index" href="genindex.html" /> <link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" /> <link rel="search" title="Search" href="search.html" />
<link rel="next" title="API Reference" href="reference.html" /> <link rel="prev" title="API Reference" href="reference.html" />
<link rel="prev" title="Getting Started Fast" href="gettingstartedfast.html" />
</head><body> </head><body>
<div class="related" role="navigation" aria-label="related navigation"> <div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3> <h3>Navigation</h3>
@@ -27,11 +26,8 @@
accesskey="I">index</a></li> accesskey="I">index</a></li>
<li class="right" > <li class="right" >
<a href="reference.html" title="API Reference" <a href="reference.html" title="API Reference"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="gettingstartedfast.html" title="Getting Started Fast"
accesskey="P">previous</a> |</li> accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.0 beta documentation</a> &#187;</li> <li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Examples</a></li> <li class="nav-item nav-item-this"><a href="">Examples</a></li>
</ul> </ul>
</div> </div>
@@ -380,7 +376,7 @@ over the network.</p>
<span class="c1"># We specify a callback that will get called every time</span> <span class="c1"># We specify a callback that will get called every time</span>
<span class="c1"># the destination receives data.</span> <span class="c1"># the destination receives data.</span>
<span class="n">broadcast_destination</span><span class="o">.</span><span class="n">packet_callback</span><span class="p">(</span><span class="n">packet_callback</span><span class="p">)</span> <span class="n">broadcast_destination</span><span class="o">.</span><span class="n">set_packet_callback</span><span class="p">(</span><span class="n">packet_callback</span><span class="p">)</span>
<span class="c1"># Everything&#39;s ready!</span> <span class="c1"># Everything&#39;s ready!</span>
<span class="c1"># Let&#39;s hand over control to the main loop</span> <span class="c1"># Let&#39;s hand over control to the main loop</span>
@@ -522,7 +518,7 @@ the Packet interface.</p>
<span class="c1"># Tell the destination which function in our program to</span> <span class="c1"># Tell the destination which function in our program to</span>
<span class="c1"># run when a packet is received. We do this so we can</span> <span class="c1"># run when a packet is received. We do this so we can</span>
<span class="c1"># print a log message when the server receives a request</span> <span class="c1"># print a log message when the server receives a request</span>
<span class="n">echo_destination</span><span class="o">.</span><span class="n">packet_callback</span><span class="p">(</span><span class="n">server_callback</span><span class="p">)</span> <span class="n">echo_destination</span><span class="o">.</span><span class="n">set_packet_callback</span><span class="p">(</span><span class="n">server_callback</span><span class="p">)</span>
<span class="c1"># Everything&#39;s ready!</span> <span class="c1"># Everything&#39;s ready!</span>
<span class="c1"># Let&#39;s Wait for client requests or user input</span> <span class="c1"># Let&#39;s Wait for client requests or user input</span>
@@ -640,12 +636,12 @@ the Packet interface.</p>
<span class="c1"># the packet times out.</span> <span class="c1"># the packet times out.</span>
<span class="k">if</span> <span class="n">timeout</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span> <span class="k">if</span> <span class="n">timeout</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">packet_receipt</span><span class="o">.</span><span class="n">set_timeout</span><span class="p">(</span><span class="n">timeout</span><span class="p">)</span> <span class="n">packet_receipt</span><span class="o">.</span><span class="n">set_timeout</span><span class="p">(</span><span class="n">timeout</span><span class="p">)</span>
<span class="n">packet_receipt</span><span class="o">.</span><span class="n">timeout_callback</span><span class="p">(</span><span class="n">packet_timed_out</span><span class="p">)</span> <span class="n">packet_receipt</span><span class="o">.</span><span class="n">set_timeout_callback</span><span class="p">(</span><span class="n">packet_timed_out</span><span class="p">)</span>
<span class="c1"># We can then set a delivery callback on the receipt.</span> <span class="c1"># We can then set a delivery callback on the receipt.</span>
<span class="c1"># This will get automatically called when a proof for</span> <span class="c1"># This will get automatically called when a proof for</span>
<span class="c1"># this specific packet is received from the destination.</span> <span class="c1"># this specific packet is received from the destination.</span>
<span class="n">packet_receipt</span><span class="o">.</span><span class="n">delivery_callback</span><span class="p">(</span><span class="n">packet_delivered</span><span class="p">)</span> <span class="n">packet_receipt</span><span class="o">.</span><span class="n">set_delivery_callback</span><span class="p">(</span><span class="n">packet_delivered</span><span class="p">)</span>
<span class="c1"># Tell the user that the echo request was sent</span> <span class="c1"># Tell the user that the echo request was sent</span>
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">&quot;Sent echo request to &quot;</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">request_destination</span><span class="o">.</span><span class="n">hash</span><span class="p">))</span> <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">&quot;Sent echo request to &quot;</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">request_destination</span><span class="o">.</span><span class="n">hash</span><span class="p">))</span>
@@ -659,7 +655,7 @@ the Packet interface.</p>
<span class="c1"># receives a proof packet.</span> <span class="c1"># receives a proof packet.</span>
<span class="k">def</span> <span class="nf">packet_delivered</span><span class="p">(</span><span class="n">receipt</span><span class="p">):</span> <span class="k">def</span> <span class="nf">packet_delivered</span><span class="p">(</span><span class="n">receipt</span><span class="p">):</span>
<span class="k">if</span> <span class="n">receipt</span><span class="o">.</span><span class="n">status</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">PacketReceipt</span><span class="o">.</span><span class="n">DELIVERED</span><span class="p">:</span> <span class="k">if</span> <span class="n">receipt</span><span class="o">.</span><span class="n">status</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">PacketReceipt</span><span class="o">.</span><span class="n">DELIVERED</span><span class="p">:</span>
<span class="n">rtt</span> <span class="o">=</span> <span class="n">receipt</span><span class="o">.</span><span class="n">rtt</span><span class="p">()</span> <span class="n">rtt</span> <span class="o">=</span> <span class="n">receipt</span><span class="o">.</span><span class="n">get_rtt</span><span class="p">()</span>
<span class="k">if</span> <span class="p">(</span><span class="n">rtt</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">):</span> <span class="k">if</span> <span class="p">(</span><span class="n">rtt</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">):</span>
<span class="n">rtt</span> <span class="o">=</span> <span class="nb">round</span><span class="p">(</span><span class="n">rtt</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span> <span class="n">rtt</span> <span class="o">=</span> <span class="nb">round</span><span class="p">(</span><span class="n">rtt</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="n">rttstring</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">rtt</span><span class="p">)</span><span class="o">+</span><span class="s2">&quot; seconds&quot;</span> <span class="n">rttstring</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">rtt</span><span class="p">)</span><span class="o">+</span><span class="s2">&quot; seconds&quot;</span>
@@ -803,7 +799,7 @@ destination, and passing traffic back and forth over the link.</p>
<span class="c1"># We configure a function that will get called every time</span> <span class="c1"># We configure a function that will get called every time</span>
<span class="c1"># a new client creates a link to this destination.</span> <span class="c1"># a new client creates a link to this destination.</span>
<span class="n">server_destination</span><span class="o">.</span><span class="n">link_established_callback</span><span class="p">(</span><span class="n">client_connected</span><span class="p">)</span> <span class="n">server_destination</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">client_connected</span><span class="p">)</span>
<span class="c1"># Everything&#39;s ready!</span> <span class="c1"># Everything&#39;s ready!</span>
<span class="c1"># Let&#39;s Wait for client requests or user input</span> <span class="c1"># Let&#39;s Wait for client requests or user input</span>
@@ -835,8 +831,8 @@ destination, and passing traffic back and forth over the link.</p>
<span class="k">global</span> <span class="n">latest_client_link</span> <span class="k">global</span> <span class="n">latest_client_link</span>
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">&quot;Client connected&quot;</span><span class="p">)</span> <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">&quot;Client connected&quot;</span><span class="p">)</span>
<span class="n">link</span><span class="o">.</span><span class="n">link_closed_callback</span><span class="p">(</span><span class="n">client_disconnected</span><span class="p">)</span> <span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">client_disconnected</span><span class="p">)</span>
<span class="n">link</span><span class="o">.</span><span class="n">packet_callback</span><span class="p">(</span><span class="n">server_packet_received</span><span class="p">)</span> <span class="n">link</span><span class="o">.</span><span class="n">set_packet_callback</span><span class="p">(</span><span class="n">server_packet_received</span><span class="p">)</span>
<span class="n">latest_client_link</span> <span class="o">=</span> <span class="n">link</span> <span class="n">latest_client_link</span> <span class="o">=</span> <span class="n">link</span>
<span class="k">def</span> <span class="nf">client_disconnected</span><span class="p">(</span><span class="n">link</span><span class="p">):</span> <span class="k">def</span> <span class="nf">client_disconnected</span><span class="p">(</span><span class="n">link</span><span class="p">):</span>
@@ -908,12 +904,12 @@ destination, and passing traffic back and forth over the link.</p>
<span class="c1"># We set a callback that will get executed</span> <span class="c1"># We set a callback that will get executed</span>
<span class="c1"># every time a packet is received over the</span> <span class="c1"># every time a packet is received over the</span>
<span class="c1"># link</span> <span class="c1"># link</span>
<span class="n">link</span><span class="o">.</span><span class="n">packet_callback</span><span class="p">(</span><span class="n">client_packet_received</span><span class="p">)</span> <span class="n">link</span><span class="o">.</span><span class="n">set_packet_callback</span><span class="p">(</span><span class="n">client_packet_received</span><span class="p">)</span>
<span class="c1"># We&#39;ll also set up functions to inform the</span> <span class="c1"># We&#39;ll also set up functions to inform the</span>
<span class="c1"># user when the link is established or closed</span> <span class="c1"># user when the link is established or closed</span>
<span class="n">link</span><span class="o">.</span><span class="n">link_established_callback</span><span class="p">(</span><span class="n">link_established</span><span class="p">)</span> <span class="n">link</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">link_established</span><span class="p">)</span>
<span class="n">link</span><span class="o">.</span><span class="n">link_closed_callback</span><span class="p">(</span><span class="n">link_closed</span><span class="p">)</span> <span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">link_closed</span><span class="p">)</span>
<span class="c1"># Everything is set up, so let&#39;s enter a loop</span> <span class="c1"># Everything is set up, so let&#39;s enter a loop</span>
<span class="c1"># for the user to interact with the example</span> <span class="c1"># for the user to interact with the example</span>
@@ -940,8 +936,18 @@ destination, and passing traffic back and forth over the link.</p>
<span class="c1"># If not, send the entered text over the link</span> <span class="c1"># If not, send the entered text over the link</span>
<span class="k">if</span> <span class="n">text</span> <span class="o">!=</span> <span class="s2">&quot;&quot;</span><span class="p">:</span> <span class="k">if</span> <span class="n">text</span> <span class="o">!=</span> <span class="s2">&quot;&quot;</span><span class="p">:</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">)</span> <span class="n">data</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">)</span>
<span class="n">RNS</span><span class="o">.</span><span class="n">Packet</span><span class="p">(</span><span class="n">server_link</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span><span class="o">.</span><span class="n">send</span><span class="p">()</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">MDU</span><span class="p">:</span>
<span class="n">RNS</span><span class="o">.</span><span class="n">Packet</span><span class="p">(</span><span class="n">server_link</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span><span class="o">.</span><span class="n">send</span><span class="p">()</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span>
<span class="s2">&quot;Cannot send this packet, the data size of &quot;</span><span class="o">+</span>
<span class="nb">str</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">))</span><span class="o">+</span><span class="s2">&quot; bytes exceeds the link packet MDU of &quot;</span><span class="o">+</span>
<span class="nb">str</span><span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">MDU</span><span class="p">)</span><span class="o">+</span><span class="s2">&quot; bytes&quot;</span><span class="p">,</span>
<span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span>
<span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span> <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">&quot;Error while sending data over the link: &quot;</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
<span class="n">should_quit</span> <span class="o">=</span> <span class="kc">True</span> <span class="n">should_quit</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">server_link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span> <span class="n">server_link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span>
@@ -1110,7 +1116,7 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
<span class="c1"># We configure a function that will get called every time</span> <span class="c1"># We configure a function that will get called every time</span>
<span class="c1"># a new client creates a link to this destination.</span> <span class="c1"># a new client creates a link to this destination.</span>
<span class="n">server_destination</span><span class="o">.</span><span class="n">link_established_callback</span><span class="p">(</span><span class="n">client_connected</span><span class="p">)</span> <span class="n">server_destination</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">client_connected</span><span class="p">)</span>
<span class="c1"># Everything&#39;s ready!</span> <span class="c1"># Everything&#39;s ready!</span>
<span class="c1"># Let&#39;s Wait for client requests or user input</span> <span class="c1"># Let&#39;s Wait for client requests or user input</span>
@@ -1147,7 +1153,7 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isdir</span><span class="p">(</span><span class="n">serve_path</span><span class="p">):</span> <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isdir</span><span class="p">(</span><span class="n">serve_path</span><span class="p">):</span>
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">&quot;Client connected, sending file list...&quot;</span><span class="p">)</span> <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">&quot;Client connected, sending file list...&quot;</span><span class="p">)</span>
<span class="n">link</span><span class="o">.</span><span class="n">link_closed_callback</span><span class="p">(</span><span class="n">client_disconnected</span><span class="p">)</span> <span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">client_disconnected</span><span class="p">)</span>
<span class="c1"># We pack a list of files for sending in a packet</span> <span class="c1"># We pack a list of files for sending in a packet</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">umsgpack</span><span class="o">.</span><span class="n">packb</span><span class="p">(</span><span class="n">list_files</span><span class="p">())</span> <span class="n">data</span> <span class="o">=</span> <span class="n">umsgpack</span><span class="o">.</span><span class="n">packb</span><span class="p">(</span><span class="n">list_files</span><span class="p">())</span>
@@ -1159,8 +1165,8 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
<span class="n">list_packet</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Packet</span><span class="p">(</span><span class="n">link</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span> <span class="n">list_packet</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Packet</span><span class="p">(</span><span class="n">link</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
<span class="n">list_receipt</span> <span class="o">=</span> <span class="n">list_packet</span><span class="o">.</span><span class="n">send</span><span class="p">()</span> <span class="n">list_receipt</span> <span class="o">=</span> <span class="n">list_packet</span><span class="o">.</span><span class="n">send</span><span class="p">()</span>
<span class="n">list_receipt</span><span class="o">.</span><span class="n">set_timeout</span><span class="p">(</span><span class="n">APP_TIMEOUT</span><span class="p">)</span> <span class="n">list_receipt</span><span class="o">.</span><span class="n">set_timeout</span><span class="p">(</span><span class="n">APP_TIMEOUT</span><span class="p">)</span>
<span class="n">list_receipt</span><span class="o">.</span><span class="n">delivery_callback</span><span class="p">(</span><span class="n">list_delivered</span><span class="p">)</span> <span class="n">list_receipt</span><span class="o">.</span><span class="n">set_delivery_callback</span><span class="p">(</span><span class="n">list_delivered</span><span class="p">)</span>
<span class="n">list_receipt</span><span class="o">.</span><span class="n">timeout_callback</span><span class="p">(</span><span class="n">list_timeout</span><span class="p">)</span> <span class="n">list_receipt</span><span class="o">.</span><span class="n">set_timeout_callback</span><span class="p">(</span><span class="n">list_timeout</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span> <span class="k">else</span><span class="p">:</span>
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">&quot;Too many files in served directory!&quot;</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span><span class="p">)</span> <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">&quot;Too many files in served directory!&quot;</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span><span class="p">)</span>
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">&quot;You should implement a function to split the filelist over multiple packets.&quot;</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span><span class="p">)</span> <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">&quot;You should implement a function to split the filelist over multiple packets.&quot;</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span><span class="p">)</span>
@@ -1170,7 +1176,7 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
<span class="c1"># open until the client requests a file. We&#39;ll</span> <span class="c1"># open until the client requests a file. We&#39;ll</span>
<span class="c1"># configure a function that get&#39;s called when</span> <span class="c1"># configure a function that get&#39;s called when</span>
<span class="c1"># the client sends a packet with a file request.</span> <span class="c1"># the client sends a packet with a file request.</span>
<span class="n">link</span><span class="o">.</span><span class="n">packet_callback</span><span class="p">(</span><span class="n">client_request</span><span class="p">)</span> <span class="n">link</span><span class="o">.</span><span class="n">set_packet_callback</span><span class="p">(</span><span class="n">client_request</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span> <span class="k">else</span><span class="p">:</span>
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">&quot;Client connected, but served path no longer exists!&quot;</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span><span class="p">)</span> <span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">&quot;Client connected, but served path no longer exists!&quot;</span><span class="p">,</span> <span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span><span class="p">)</span>
<span class="n">link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span> <span class="n">link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span>
@@ -1299,18 +1305,18 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
<span class="c1"># We expect any normal data packets on the link</span> <span class="c1"># We expect any normal data packets on the link</span>
<span class="c1"># to contain a list of served files, so we set</span> <span class="c1"># to contain a list of served files, so we set</span>
<span class="c1"># a callback accordingly</span> <span class="c1"># a callback accordingly</span>
<span class="n">link</span><span class="o">.</span><span class="n">packet_callback</span><span class="p">(</span><span class="n">filelist_received</span><span class="p">)</span> <span class="n">link</span><span class="o">.</span><span class="n">set_packet_callback</span><span class="p">(</span><span class="n">filelist_received</span><span class="p">)</span>
<span class="c1"># We&#39;ll also set up functions to inform the</span> <span class="c1"># We&#39;ll also set up functions to inform the</span>
<span class="c1"># user when the link is established or closed</span> <span class="c1"># user when the link is established or closed</span>
<span class="n">link</span><span class="o">.</span><span class="n">link_established_callback</span><span class="p">(</span><span class="n">link_established</span><span class="p">)</span> <span class="n">link</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">link_established</span><span class="p">)</span>
<span class="n">link</span><span class="o">.</span><span class="n">link_closed_callback</span><span class="p">(</span><span class="n">link_closed</span><span class="p">)</span> <span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">link_closed</span><span class="p">)</span>
<span class="c1"># And set the link to automatically begin</span> <span class="c1"># And set the link to automatically begin</span>
<span class="c1"># downloading advertised resources</span> <span class="c1"># downloading advertised resources</span>
<span class="n">link</span><span class="o">.</span><span class="n">set_resource_strategy</span><span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">ACCEPT_ALL</span><span class="p">)</span> <span class="n">link</span><span class="o">.</span><span class="n">set_resource_strategy</span><span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">ACCEPT_ALL</span><span class="p">)</span>
<span class="n">link</span><span class="o">.</span><span class="n">resource_started_callback</span><span class="p">(</span><span class="n">download_began</span><span class="p">)</span> <span class="n">link</span><span class="o">.</span><span class="n">set_resource_started_callback</span><span class="p">(</span><span class="n">download_began</span><span class="p">)</span>
<span class="n">link</span><span class="o">.</span><span class="n">resource_concluded_callback</span><span class="p">(</span><span class="n">download_concluded</span><span class="p">)</span> <span class="n">link</span><span class="o">.</span><span class="n">set_resource_concluded_callback</span><span class="p">(</span><span class="n">download_concluded</span><span class="p">)</span>
<span class="n">menu</span><span class="p">()</span> <span class="n">menu</span><span class="p">()</span>
@@ -1667,11 +1673,8 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
</ul> </ul>
<h4>Previous topic</h4> <h4>Previous topic</h4>
<p class="topless"><a href="gettingstartedfast.html"
title="previous chapter">Getting Started Fast</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="reference.html" <p class="topless"><a href="reference.html"
title="next chapter">API Reference</a></p> title="previous chapter">API Reference</a></p>
<div role="note" aria-label="source link"> <div role="note" aria-label="source link">
<h3>This Page</h3> <h3>This Page</h3>
<ul class="this-page-menu"> <ul class="this-page-menu">
@@ -1701,11 +1704,8 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
>index</a></li> >index</a></li>
<li class="right" > <li class="right" >
<a href="reference.html" title="API Reference" <a href="reference.html" title="API Reference"
>next</a> |</li>
<li class="right" >
<a href="gettingstartedfast.html" title="Getting Started Fast"
>previous</a> |</li> >previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.0 beta documentation</a> &#187;</li> <li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Examples</a></li> <li class="nav-item nav-item-this"><a href="">Examples</a></li>
</ul> </ul>
</div> </div>
+49 -37
View File
@@ -5,7 +5,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Index &#8212; Reticulum Network Stack 0.2.0 beta documentation</title> <title>Index &#8212; Reticulum Network Stack 0.2.1 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" /> <link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -23,7 +23,7 @@
<li class="right" style="margin-right: 10px"> <li class="right" style="margin-right: 10px">
<a href="#" title="General Index" <a href="#" title="General Index"
accesskey="I">index</a></li> accesskey="I">index</a></li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.0 beta documentation</a> &#187;</li> <li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Index</a></li> <li class="nav-item nav-item-this"><a href="">Index</a></li>
</ul> </ul>
</div> </div>
@@ -80,8 +80,12 @@
<td style="width: 33%; vertical-align: top;"><ul> <td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#RNS.Destination.create_keys">create_keys() (RNS.Destination method)</a> <li><a href="reference.html#RNS.Destination.create_keys">create_keys() (RNS.Destination method)</a>
</li> </li>
<li><a href="reference.html#RNS.Link.CURVE">CURVE (RNS.Link attribute)</a> <li><a href="reference.html#RNS.Identity.CURVE">CURVE (RNS.Identity attribute)</a>
<ul>
<li><a href="reference.html#RNS.Link.CURVE">(RNS.Link attribute)</a>
</li> </li>
</ul></li>
</ul></td> </ul></td>
</tr></table> </tr></table>
@@ -98,8 +102,6 @@
</li> </li>
</ul></td> </ul></td>
<td style="width: 33%; vertical-align: top;"><ul> <td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#RNS.PacketReceipt.delivery_callback">delivery_callback() (RNS.PacketReceipt method)</a>
</li>
<li><a href="reference.html#RNS.Transport.deregister_announce_handler">deregister_announce_handler() (RNS.Transport static method)</a> <li><a href="reference.html#RNS.Transport.deregister_announce_handler">deregister_announce_handler() (RNS.Transport static method)</a>
</li> </li>
<li><a href="reference.html#RNS.Destination">Destination (class in RNS)</a> <li><a href="reference.html#RNS.Destination">Destination (class in RNS)</a>
@@ -119,11 +121,17 @@
</li> </li>
</ul></li> </ul></li>
</ul></td> </ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#RNS.Packet.ENCRYPTED_MDU">ENCRYPTED_MDU (RNS.Packet attribute)</a>
</li>
</ul></td>
</tr></table> </tr></table>
<h2 id="F">F</h2> <h2 id="F">F</h2>
<table style="width: 100%" class="indextable genindextable"><tr> <table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul> <td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#RNS.Identity.from_bytes">from_bytes() (RNS.Identity static method)</a>
</li>
<li><a href="reference.html#RNS.Identity.from_file">from_file() (RNS.Identity static method)</a> <li><a href="reference.html#RNS.Identity.from_file">from_file() (RNS.Identity static method)</a>
</li> </li>
</ul></td> </ul></td>
@@ -144,11 +152,13 @@
<li><a href="reference.html#RNS.Identity.get_private_key">(RNS.Identity method)</a> <li><a href="reference.html#RNS.Identity.get_private_key">(RNS.Identity method)</a>
</li> </li>
</ul></li> </ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#RNS.Identity.get_public_key">get_public_key() (RNS.Identity method)</a> <li><a href="reference.html#RNS.Identity.get_public_key">get_public_key() (RNS.Identity method)</a>
</li> </li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#RNS.Identity.get_random_hash">get_random_hash() (RNS.Identity static method)</a> <li><a href="reference.html#RNS.Identity.get_random_hash">get_random_hash() (RNS.Identity static method)</a>
</li>
<li><a href="reference.html#RNS.PacketReceipt.get_rtt">get_rtt() (RNS.PacketReceipt method)</a>
</li> </li>
<li><a href="reference.html#RNS.PacketReceipt.get_status">get_status() (RNS.PacketReceipt method)</a> <li><a href="reference.html#RNS.PacketReceipt.get_status">get_status() (RNS.PacketReceipt method)</a>
</li> </li>
@@ -198,16 +208,14 @@
<td style="width: 33%; vertical-align: top;"><ul> <td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#RNS.Link">Link (class in RNS)</a> <li><a href="reference.html#RNS.Link">Link (class in RNS)</a>
</li> </li>
<li><a href="reference.html#RNS.Destination.link_established_callback">link_established_callback() (RNS.Destination method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#RNS.Destination.load_private_key">load_private_key() (RNS.Destination method)</a> <li><a href="reference.html#RNS.Destination.load_private_key">load_private_key() (RNS.Destination method)</a>
<ul> <ul>
<li><a href="reference.html#RNS.Identity.load_private_key">(RNS.Identity method)</a> <li><a href="reference.html#RNS.Identity.load_private_key">(RNS.Identity method)</a>
</li> </li>
</ul></li> </ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#RNS.Identity.load_public_key">load_public_key() (RNS.Identity method)</a> <li><a href="reference.html#RNS.Identity.load_public_key">load_public_key() (RNS.Identity method)</a>
</li> </li>
</ul></td> </ul></td>
@@ -230,19 +238,13 @@
<td style="width: 33%; vertical-align: top;"><ul> <td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#RNS.Packet">Packet (class in RNS)</a> <li><a href="reference.html#RNS.Packet">Packet (class in RNS)</a>
</li> </li>
<li><a href="reference.html#RNS.Destination.packet_callback">packet_callback() (RNS.Destination method)</a>
<ul>
<li><a href="reference.html#RNS.Link.packet_callback">(RNS.Link method)</a>
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#RNS.PacketReceipt">PacketReceipt (class in RNS)</a> <li><a href="reference.html#RNS.PacketReceipt">PacketReceipt (class in RNS)</a>
</li> </li>
<li><a href="reference.html#RNS.Resource.progress">progress() (RNS.Resource method)</a> </ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#RNS.Packet.PLAIN_MDU">PLAIN_MDU (RNS.Packet attribute)</a>
</li> </li>
<li><a href="reference.html#RNS.Destination.proof_requested_callback">proof_requested_callback() (RNS.Destination method)</a> <li><a href="reference.html#RNS.Resource.progress">progress() (RNS.Resource method)</a>
</li> </li>
</ul></td> </ul></td>
</tr></table> </tr></table>
@@ -256,23 +258,15 @@
</li> </li>
<li><a href="reference.html#RNS.Transport.register_announce_handler">register_announce_handler() (RNS.Transport static method)</a> <li><a href="reference.html#RNS.Transport.register_announce_handler">register_announce_handler() (RNS.Transport static method)</a>
</li> </li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#RNS.Transport.request_path">request_path() (RNS.Transport static method)</a> <li><a href="reference.html#RNS.Transport.request_path">request_path() (RNS.Transport static method)</a>
</li> </li>
<li><a href="reference.html#RNS.Packet.resend">resend() (RNS.Packet method)</a> <li><a href="reference.html#RNS.Packet.resend">resend() (RNS.Packet method)</a>
</li> </li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#RNS.Resource">Resource (class in RNS)</a> <li><a href="reference.html#RNS.Resource">Resource (class in RNS)</a>
</li>
<li><a href="reference.html#RNS.Link.resource_callback">resource_callback() (RNS.Link method)</a>
</li>
<li><a href="reference.html#RNS.Link.resource_concluded_callback">resource_concluded_callback() (RNS.Link method)</a>
</li>
<li><a href="reference.html#RNS.Link.resource_started_callback">resource_started_callback() (RNS.Link method)</a>
</li> </li>
<li><a href="reference.html#RNS.Reticulum">Reticulum (class in RNS)</a> <li><a href="reference.html#RNS.Reticulum">Reticulum (class in RNS)</a>
</li>
<li><a href="reference.html#RNS.PacketReceipt.rtt">rtt() (RNS.PacketReceipt method)</a>
</li> </li>
</ul></td> </ul></td>
</tr></table> </tr></table>
@@ -283,14 +277,34 @@
<li><a href="reference.html#RNS.Packet.send">send() (RNS.Packet method)</a> <li><a href="reference.html#RNS.Packet.send">send() (RNS.Packet method)</a>
</li> </li>
<li><a href="reference.html#RNS.Destination.set_default_app_data">set_default_app_data() (RNS.Destination method)</a> <li><a href="reference.html#RNS.Destination.set_default_app_data">set_default_app_data() (RNS.Destination method)</a>
</li>
<li><a href="reference.html#RNS.PacketReceipt.set_delivery_callback">set_delivery_callback() (RNS.PacketReceipt method)</a>
</li>
<li><a href="reference.html#RNS.Destination.set_link_established_callback">set_link_established_callback() (RNS.Destination method)</a>
</li>
<li><a href="reference.html#RNS.Destination.set_packet_callback">set_packet_callback() (RNS.Destination method)</a>
<ul>
<li><a href="reference.html#RNS.Link.set_packet_callback">(RNS.Link method)</a>
</li>
</ul></li>
<li><a href="reference.html#RNS.Destination.set_proof_requested_callback">set_proof_requested_callback() (RNS.Destination method)</a>
</li> </li>
<li><a href="reference.html#RNS.Destination.set_proof_strategy">set_proof_strategy() (RNS.Destination method)</a> <li><a href="reference.html#RNS.Destination.set_proof_strategy">set_proof_strategy() (RNS.Destination method)</a>
</li> </li>
<li><a href="reference.html#RNS.Link.set_resource_strategy">set_resource_strategy() (RNS.Link method)</a> <li><a href="reference.html#RNS.Link.set_resource_callback">set_resource_callback() (RNS.Link method)</a>
</li> </li>
</ul></td> </ul></td>
<td style="width: 33%; vertical-align: top;"><ul> <td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#RNS.Link.set_resource_concluded_callback">set_resource_concluded_callback() (RNS.Link method)</a>
</li>
<li><a href="reference.html#RNS.Link.set_resource_started_callback">set_resource_started_callback() (RNS.Link method)</a>
</li>
<li><a href="reference.html#RNS.Link.set_resource_strategy">set_resource_strategy() (RNS.Link method)</a>
</li>
<li><a href="reference.html#RNS.PacketReceipt.set_timeout">set_timeout() (RNS.PacketReceipt method)</a> <li><a href="reference.html#RNS.PacketReceipt.set_timeout">set_timeout() (RNS.PacketReceipt method)</a>
</li>
<li><a href="reference.html#RNS.PacketReceipt.set_timeout_callback">set_timeout_callback() (RNS.PacketReceipt method)</a>
</li> </li>
<li><a href="reference.html#RNS.Reticulum.should_allow_unencrypted">should_allow_unencrypted() (RNS.Reticulum static method)</a> <li><a href="reference.html#RNS.Reticulum.should_allow_unencrypted">should_allow_unencrypted() (RNS.Reticulum static method)</a>
</li> </li>
@@ -309,15 +323,13 @@
<table style="width: 100%" class="indextable genindextable"><tr> <table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul> <td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#RNS.Link.teardown">teardown() (RNS.Link method)</a> <li><a href="reference.html#RNS.Link.teardown">teardown() (RNS.Link method)</a>
</li>
<li><a href="reference.html#RNS.PacketReceipt.timeout_callback">timeout_callback() (RNS.PacketReceipt method)</a>
</li> </li>
<li><a href="reference.html#RNS.Identity.to_file">to_file() (RNS.Identity method)</a> <li><a href="reference.html#RNS.Identity.to_file">to_file() (RNS.Identity method)</a>
</li>
<li><a href="reference.html#RNS.Transport">Transport (class in RNS)</a>
</li> </li>
</ul></td> </ul></td>
<td style="width: 33%; vertical-align: top;"><ul> <td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#RNS.Transport">Transport (class in RNS)</a>
</li>
<li><a href="reference.html#RNS.Reticulum.transport_enabled">transport_enabled() (RNS.Reticulum static method)</a> <li><a href="reference.html#RNS.Reticulum.transport_enabled">transport_enabled() (RNS.Reticulum static method)</a>
</li> </li>
<li><a href="reference.html#RNS.Identity.truncated_hash">truncated_hash() (RNS.Identity static method)</a> <li><a href="reference.html#RNS.Identity.truncated_hash">truncated_hash() (RNS.Identity static method)</a>
@@ -363,7 +375,7 @@
<li class="right" style="margin-right: 10px"> <li class="right" style="margin-right: 10px">
<a href="#" title="General Index" <a href="#" title="General Index"
>index</a></li> >index</a></li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.0 beta documentation</a> &#187;</li> <li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Index</a></li> <li class="nav-item nav-item-this"><a href="">Index</a></li>
</ul> </ul>
</div> </div>
+4 -5
View File
@@ -5,7 +5,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Getting Started Fast &#8212; Reticulum Network Stack 0.2.0 beta documentation</title> <title>Getting Started Fast &#8212; Reticulum Network Stack 0.2.1 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" /> <link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -31,7 +31,7 @@
<li class="right" > <li class="right" >
<a href="whatis.html" title="What is Reticulum?" <a href="whatis.html" title="What is Reticulum?"
accesskey="P">previous</a> |</li> accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.0 beta documentation</a> &#187;</li> <li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Getting Started Fast</a></li> <li class="nav-item nav-item-this"><a href="">Getting Started Fast</a></li>
</ul> </ul>
</div> </div>
@@ -43,7 +43,6 @@
<div class="section" id="getting-started-fast"> <div class="section" id="getting-started-fast">
<h1>Getting Started Fast<a class="headerlink" href="#getting-started-fast" title="Permalink to this headline"></a></h1> <h1>Getting Started Fast<a class="headerlink" href="#getting-started-fast" title="Permalink to this headline"></a></h1>
<p>What do we want to do? Something! When do we want to do it? Right now! Lets go.</p>
<p>The best way to get started with the Reticulum Network Stack depends on what <p>The best way to get started with the Reticulum Network Stack depends on what
you want to do. This guide will outline sensible starting paths for different you want to do. This guide will outline sensible starting paths for different
scenarios.</p> scenarios.</p>
@@ -60,7 +59,7 @@ in the development for the messaging and information-sharing protocol
<div class="section" id="develop-a-program-with-reticulum"> <div class="section" id="develop-a-program-with-reticulum">
<h2>Develop a Program with Reticulum<a class="headerlink" href="#develop-a-program-with-reticulum" title="Permalink to this headline"></a></h2> <h2>Develop a Program with Reticulum<a class="headerlink" href="#develop-a-program-with-reticulum" title="Permalink to this headline"></a></h2>
<p>If you want to develop programs that use Reticulum, the easiest way to get <p>If you want to develop programs that use Reticulum, the easiest way to get
started is to install Reticulum via pip:</p> started is to install the latest release of Reticulum via pip:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip3</span> <span class="n">install</span> <span class="n">rns</span> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip3</span> <span class="n">install</span> <span class="n">rns</span>
</pre></div> </pre></div>
</div> </div>
@@ -167,7 +166,7 @@ dont use pip, but try this recipe:</p>
<li class="right" > <li class="right" >
<a href="whatis.html" title="What is Reticulum?" <a href="whatis.html" title="What is Reticulum?"
>previous</a> |</li> >previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.0 beta documentation</a> &#187;</li> <li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Getting Started Fast</a></li> <li class="nav-item nav-item-this"><a href="">Getting Started Fast</a></li>
</ul> </ul>
</div> </div>
+33 -32
View File
@@ -5,7 +5,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Reticulum Network Stack Manual &#8212; Reticulum Network Stack 0.2.0 beta documentation</title> <title>Reticulum Network Stack Manual &#8212; Reticulum Network Stack 0.2.1 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" /> <link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -27,7 +27,7 @@
<li class="right" > <li class="right" >
<a href="whatis.html" title="What is Reticulum?" <a href="whatis.html" title="What is Reticulum?"
accesskey="N">next</a> |</li> accesskey="N">next</a> |</li>
<li class="nav-item nav-item-0"><a href="#">Reticulum Network Stack 0.2.0 beta documentation</a> &#187;</li> <li class="nav-item nav-item-0"><a href="#">Reticulum Network Stack 0.2.1 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Reticulum Network Stack Manual</a></li> <li class="nav-item nav-item-this"><a href="">Reticulum Network Stack Manual</a></li>
</ul> </ul>
</div> </div>
@@ -58,13 +58,29 @@ the development of Reticulum itself.</p>
<li class="toctree-l2"><a class="reference internal" href="gettingstartedfast.html#participate-in-reticulum-development">Participate in Reticulum Development</a></li> <li class="toctree-l2"><a class="reference internal" href="gettingstartedfast.html#participate-in-reticulum-development">Participate in Reticulum Development</a></li>
</ul> </ul>
</li> </li>
<li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a><ul> <li class="toctree-l1"><a class="reference internal" href="understanding.html">Understanding Reticulum</a><ul>
<li class="toctree-l2"><a class="reference internal" href="examples.html#minimal">Minimal</a></li> <li class="toctree-l2"><a class="reference internal" href="understanding.html#motivation">Motivation</a></li>
<li class="toctree-l2"><a class="reference internal" href="examples.html#announce">Announce</a></li> <li class="toctree-l2"><a class="reference internal" href="understanding.html#goals">Goals</a></li>
<li class="toctree-l2"><a class="reference internal" href="examples.html#broadcast">Broadcast</a></li> <li class="toctree-l2"><a class="reference internal" href="understanding.html#introduction-basic-functionality">Introduction &amp; Basic Functionality</a><ul>
<li class="toctree-l2"><a class="reference internal" href="examples.html#echo">Echo</a></li> <li class="toctree-l3"><a class="reference internal" href="understanding.html#destinations">Destinations</a></li>
<li class="toctree-l2"><a class="reference internal" href="examples.html#link">Link</a></li> <li class="toctree-l3"><a class="reference internal" href="understanding.html#public-key-announcements">Public Key Announcements</a></li>
<li class="toctree-l2"><a class="reference internal" href="examples.html#filetransfer">Filetransfer</a></li> <li class="toctree-l3"><a class="reference internal" href="understanding.html#understanding-identities">Identities</a></li>
<li class="toctree-l3"><a class="reference internal" href="understanding.html#getting-further">Getting Further</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="understanding.html#reticulum-transport">Reticulum Transport</a><ul>
<li class="toctree-l3"><a class="reference internal" href="understanding.html#the-announce-mechanism-in-detail">The Announce Mechanism in Detail</a></li>
<li class="toctree-l3"><a class="reference internal" href="understanding.html#reaching-the-destination">Reaching the Destination</a></li>
<li class="toctree-l3"><a class="reference internal" href="understanding.html#resources">Resources</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="understanding.html#reference-system-setup">Reference System Setup</a></li>
<li class="toctree-l2"><a class="reference internal" href="understanding.html#protocol-specifics">Protocol Specifics</a><ul>
<li class="toctree-l3"><a class="reference internal" href="understanding.html#node-types">Node Types</a></li>
<li class="toctree-l3"><a class="reference internal" href="understanding.html#packet-prioritisation">Packet Prioritisation</a></li>
<li class="toctree-l3"><a class="reference internal" href="understanding.html#binary-packet-format">Binary Packet Format</a></li>
</ul>
</li>
</ul> </ul>
</li> </li>
<li class="toctree-l1"><a class="reference internal" href="reference.html">API Reference</a><ul> <li class="toctree-l1"><a class="reference internal" href="reference.html">API Reference</a><ul>
@@ -81,28 +97,13 @@ the development of Reticulum itself.</p>
</li> </li>
</ul> </ul>
</li> </li>
<li class="toctree-l1"><a class="reference internal" href="understanding.html">Understanding Reticulum</a><ul> <li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a><ul>
<li class="toctree-l2"><a class="reference internal" href="understanding.html#motivation">Motivation</a></li> <li class="toctree-l2"><a class="reference internal" href="examples.html#minimal">Minimal</a></li>
<li class="toctree-l2"><a class="reference internal" href="understanding.html#goals">Goals</a></li> <li class="toctree-l2"><a class="reference internal" href="examples.html#announce">Announce</a></li>
<li class="toctree-l2"><a class="reference internal" href="understanding.html#introduction-basic-functionality">Introduction &amp; Basic Functionality</a><ul> <li class="toctree-l2"><a class="reference internal" href="examples.html#broadcast">Broadcast</a></li>
<li class="toctree-l3"><a class="reference internal" href="understanding.html#destinations">Destinations</a></li> <li class="toctree-l2"><a class="reference internal" href="examples.html#echo">Echo</a></li>
<li class="toctree-l3"><a class="reference internal" href="understanding.html#public-key-announcements">Public Key Announcements</a></li> <li class="toctree-l2"><a class="reference internal" href="examples.html#link">Link</a></li>
<li class="toctree-l3"><a class="reference internal" href="understanding.html#understanding-identities">Identities</a></li> <li class="toctree-l2"><a class="reference internal" href="examples.html#filetransfer">Filetransfer</a></li>
<li class="toctree-l3"><a class="reference internal" href="understanding.html#getting-further">Getting Further</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="understanding.html#reticulum-transport">Reticulum Transport</a><ul>
<li class="toctree-l3"><a class="reference internal" href="understanding.html#reaching-the-destination">Reaching the Destination</a></li>
<li class="toctree-l3"><a class="reference internal" href="understanding.html#resources">Resources</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="understanding.html#reference-system-setup">Reference System Setup</a></li>
<li class="toctree-l2"><a class="reference internal" href="understanding.html#protocol-specifics">Protocol Specifics</a><ul>
<li class="toctree-l3"><a class="reference internal" href="understanding.html#node-types">Node Types</a></li>
<li class="toctree-l3"><a class="reference internal" href="understanding.html#packet-prioritisation">Packet Prioritisation</a></li>
<li class="toctree-l3"><a class="reference internal" href="understanding.html#binary-packet-format">Binary Packet Format</a></li>
</ul>
</li>
</ul> </ul>
</li> </li>
</ul> </ul>
@@ -164,7 +165,7 @@ the development of Reticulum itself.</p>
<li class="right" > <li class="right" >
<a href="whatis.html" title="What is Reticulum?" <a href="whatis.html" title="What is Reticulum?"
>next</a> |</li> >next</a> |</li>
<li class="nav-item nav-item-0"><a href="#">Reticulum Network Stack 0.2.0 beta documentation</a> &#187;</li> <li class="nav-item nav-item-0"><a href="#">Reticulum Network Stack 0.2.1 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Reticulum Network Stack Manual</a></li> <li class="nav-item nav-item-this"><a href="">Reticulum Network Stack Manual</a></li>
</ul> </ul>
</div> </div>
Binary file not shown.
+91 -53
View File
@@ -5,7 +5,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>API Reference &#8212; Reticulum Network Stack 0.2.0 beta documentation</title> <title>API Reference &#8212; Reticulum Network Stack 0.2.1 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" /> <link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -16,8 +16,8 @@
<link rel="index" title="Index" href="genindex.html" /> <link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" /> <link rel="search" title="Search" href="search.html" />
<link rel="next" title="Understanding Reticulum" href="understanding.html" /> <link rel="next" title="Examples" href="examples.html" />
<link rel="prev" title="Examples" href="examples.html" /> <link rel="prev" title="Understanding Reticulum" href="understanding.html" />
</head><body> </head><body>
<div class="related" role="navigation" aria-label="related navigation"> <div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3> <h3>Navigation</h3>
@@ -26,12 +26,12 @@
<a href="genindex.html" title="General Index" <a href="genindex.html" title="General Index"
accesskey="I">index</a></li> accesskey="I">index</a></li>
<li class="right" > <li class="right" >
<a href="understanding.html" title="Understanding Reticulum" <a href="examples.html" title="Examples"
accesskey="N">next</a> |</li> accesskey="N">next</a> |</li>
<li class="right" > <li class="right" >
<a href="examples.html" title="Examples" <a href="understanding.html" title="Understanding Reticulum"
accesskey="P">previous</a> |</li> accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.0 beta documentation</a> &#187;</li> <li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">API Reference</a></li> <li class="nav-item nav-item-this"><a href="">API Reference</a></li>
</ul> </ul>
</div> </div>
@@ -117,26 +117,32 @@ and pass announces over the network.</p>
<span id="identity"></span><h3>Identity<a class="headerlink" href="#api-identity" title="Permalink to this headline"></a></h3> <span id="identity"></span><h3>Identity<a class="headerlink" href="#api-identity" title="Permalink to this headline"></a></h3>
<dl class="py class"> <dl class="py class">
<dt class="sig sig-object py" id="RNS.Identity"> <dt class="sig sig-object py" id="RNS.Identity">
<em class="property"><span class="pre">class</span> </em><span class="sig-prename descclassname"><span class="pre">RNS.</span></span><span class="sig-name descname"><span class="pre">Identity</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">public_only</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Identity" title="Permalink to this definition"></a></dt> <em class="property"><span class="pre">class</span> </em><span class="sig-prename descclassname"><span class="pre">RNS.</span></span><span class="sig-name descname"><span class="pre">Identity</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">create_keys</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Identity" title="Permalink to this definition"></a></dt>
<dd><p>This class is used to manage identities in Reticulum. It provides methods <dd><p>This class is used to manage identities in Reticulum. It provides methods
for encryption, decryption, signatures and verification, and is the basis for encryption, decryption, signatures and verification, and is the basis
for all encrypted communication over Reticulum networks.</p> for all encrypted communication over Reticulum networks.</p>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>public_only</strong> Specifies whether this destination only holds a public key.</p> <dd class="field-odd"><p><strong>create_keys</strong> Specifies whether new encryption and signing keys should be generated.</p>
</dd> </dd>
</dl> </dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="RNS.Identity.CURVE">
<span class="sig-name descname"><span class="pre">CURVE</span></span><em class="property"> <span class="pre">=</span> <span class="pre">'Curve25519'</span></em><a class="headerlink" href="#RNS.Identity.CURVE" title="Permalink to this definition"></a></dt>
<dd><p>The curve used for Elliptic Curve DH key exchanges</p>
</dd></dl>
<dl class="py attribute"> <dl class="py attribute">
<dt class="sig sig-object py" id="RNS.Identity.KEYSIZE"> <dt class="sig sig-object py" id="RNS.Identity.KEYSIZE">
<span class="sig-name descname"><span class="pre">KEYSIZE</span></span><em class="property"> <span class="pre">=</span> <span class="pre">1024</span></em><a class="headerlink" href="#RNS.Identity.KEYSIZE" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">KEYSIZE</span></span><em class="property"> <span class="pre">=</span> <span class="pre">512</span></em><a class="headerlink" href="#RNS.Identity.KEYSIZE" title="Permalink to this definition"></a></dt>
<dd><p>RSA key size in bits.</p> <dd><p>X25519 key size in bits. A complete key is the concatenation of a 256 bit encryption key, and a 256 bit signing key.</p>
</dd></dl> </dd></dl>
<dl class="py attribute"> <dl class="py attribute">
<dt class="sig sig-object py" id="RNS.Identity.TRUNCATED_HASHLENGTH"> <dt class="sig sig-object py" id="RNS.Identity.TRUNCATED_HASHLENGTH">
<span class="sig-name descname"><span class="pre">TRUNCATED_HASHLENGTH</span></span><em class="property"> <span class="pre">=</span> <span class="pre">80</span></em><a class="headerlink" href="#RNS.Identity.TRUNCATED_HASHLENGTH" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">TRUNCATED_HASHLENGTH</span></span><em class="property"> <span class="pre">=</span> <span class="pre">80</span></em><a class="headerlink" href="#RNS.Identity.TRUNCATED_HASHLENGTH" title="Permalink to this definition"></a></dt>
<dd><p>Constant specifying the truncated hash length (in bits) used by Reticulum <dd><p>Constant specifying the truncated hash length (in bits) used by Reticulum
for addressable hashes. Non-configurable.</p> for addressable hashes and other purposes. Non-configurable.</p>
</dd></dl> </dd></dl>
<dl class="py method"> <dl class="py method">
@@ -224,6 +230,21 @@ Can be used to load previously created and saved identities into Reticulum.</p>
</dl> </dl>
</dd></dl> </dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="RNS.Identity.from_bytes">
<em class="property"><span class="pre">static</span> </em><span class="sig-name descname"><span class="pre">from_bytes</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">prv_bytes</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Identity.from_bytes" title="Permalink to this definition"></a></dt>
<dd><p>Create a new <a class="reference internal" href="#api-identity"><span class="std std-ref">RNS.Identity</span></a> instance from <em>bytes</em> of private key.
Can be used to load previously created and saved identities into Reticulum.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>prv_bytes</strong> The <em>bytes</em> of private a saved private key. <strong>HAZARD!</strong> Never not use this to generate a new key by feeding random data in prv_bytes.</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>A <a class="reference internal" href="#api-identity"><span class="std std-ref">RNS.Identity</span></a> instance, or <em>None</em> if the <em>bytes</em> data was invalid.</p>
</dd>
</dl>
</dd></dl>
<dl class="py method"> <dl class="py method">
<dt class="sig sig-object py" id="RNS.Identity.get_private_key"> <dt class="sig sig-object py" id="RNS.Identity.get_private_key">
<span class="sig-name descname"><span class="pre">get_private_key</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Identity.get_private_key" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">get_private_key</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Identity.get_private_key" title="Permalink to this definition"></a></dt>
@@ -260,11 +281,11 @@ Can be used to load previously created and saved identities into Reticulum.</p>
<dl class="py method"> <dl class="py method">
<dt class="sig sig-object py" id="RNS.Identity.load_public_key"> <dt class="sig sig-object py" id="RNS.Identity.load_public_key">
<span class="sig-name descname"><span class="pre">load_public_key</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">key</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Identity.load_public_key" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">load_public_key</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">pub_bytes</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Identity.load_public_key" title="Permalink to this definition"></a></dt>
<dd><p>Load a public key into the instance.</p> <dd><p>Load a public key into the instance.</p>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>prv_bytes</strong> The public key as <em>bytes</em>.</p> <dd class="field-odd"><p><strong>pub_bytes</strong> The public key as <em>bytes</em>.</p>
</dd> </dd>
<dt class="field-even">Returns</dt> <dt class="field-even">Returns</dt>
<dd class="field-even"><p>True if the key was loaded, otherwise False.</p> <dd class="field-even"><p>True if the key was loaded, otherwise False.</p>
@@ -297,17 +318,17 @@ communication for the identity. Be very careful with this method.</p>
<dd class="field-odd"><p><strong>plaintext</strong> The plaintext to be encrypted as <em>bytes</em>.</p> <dd class="field-odd"><p><strong>plaintext</strong> The plaintext to be encrypted as <em>bytes</em>.</p>
</dd> </dd>
<dt class="field-even">Returns</dt> <dt class="field-even">Returns</dt>
<dd class="field-even"><p>Ciphertext as <em>bytes</em>.</p> <dd class="field-even"><p>Ciphertext token as <em>bytes</em>.</p>
</dd> </dd>
<dt class="field-odd">Raises</dt> <dt class="field-odd">Raises</dt>
<dd class="field-odd"><p><em>KeyError</em> if the instance does not hold a public key</p> <dd class="field-odd"><p><em>KeyError</em> if the instance does not hold a public key.</p>
</dd> </dd>
</dl> </dl>
</dd></dl> </dd></dl>
<dl class="py method"> <dl class="py method">
<dt class="sig sig-object py" id="RNS.Identity.decrypt"> <dt class="sig sig-object py" id="RNS.Identity.decrypt">
<span class="sig-name descname"><span class="pre">decrypt</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">ciphertext</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Identity.decrypt" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">decrypt</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">ciphertext_token</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Identity.decrypt" title="Permalink to this definition"></a></dt>
<dd><p>Decrypts information for the identity.</p> <dd><p>Decrypts information for the identity.</p>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters</dt>
@@ -317,7 +338,7 @@ communication for the identity. Be very careful with this method.</p>
<dd class="field-even"><p>Plaintext as <em>bytes</em>, or <em>None</em> if decryption fails.</p> <dd class="field-even"><p>Plaintext as <em>bytes</em>, or <em>None</em> if decryption fails.</p>
</dd> </dd>
<dt class="field-odd">Raises</dt> <dt class="field-odd">Raises</dt>
<dd class="field-odd"><p><em>KeyError</em> if the instance does not hold a private key</p> <dd class="field-odd"><p><em>KeyError</em> if the instance does not hold a private key.</p>
</dd> </dd>
</dl> </dl>
</dd></dl> </dd></dl>
@@ -334,7 +355,7 @@ communication for the identity. Be very careful with this method.</p>
<dd class="field-even"><p>Signature as <em>bytes</em>.</p> <dd class="field-even"><p>Signature as <em>bytes</em>.</p>
</dd> </dd>
<dt class="field-odd">Raises</dt> <dt class="field-odd">Raises</dt>
<dd class="field-odd"><p><em>KeyError</em> if the instance does not hold a private key</p> <dd class="field-odd"><p><em>KeyError</em> if the instance does not hold a private key.</p>
</dd> </dd>
</dl> </dl>
</dd></dl> </dd></dl>
@@ -354,7 +375,7 @@ communication for the identity. Be very careful with this method.</p>
<dd class="field-even"><p>True if the signature is valid, otherwise False.</p> <dd class="field-even"><p>True if the signature is valid, otherwise False.</p>
</dd> </dd>
<dt class="field-odd">Raises</dt> <dt class="field-odd">Raises</dt>
<dd class="field-odd"><p><em>KeyError</em> if the instance does not hold a public key</p> <dd class="field-odd"><p><em>KeyError</em> if the instance does not hold a public key.</p>
</dd> </dd>
</dl> </dl>
</dd></dl> </dd></dl>
@@ -427,8 +448,8 @@ encrypted communication with it.</p>
<dl class="py method"> <dl class="py method">
<dt class="sig sig-object py" id="RNS.Destination.announce"> <dt class="sig sig-object py" id="RNS.Destination.announce">
<span class="sig-name descname"><span class="pre">announce</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">app_data</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">path_response</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.announce" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">announce</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">app_data</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">path_response</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.announce" title="Permalink to this definition"></a></dt>
<dd><p>Creates an announce packet for this destination and broadcasts it on <dd><p>Creates an announce packet for this destination and broadcasts it on all
all interfaces. Application specific data can be added to the announce.</p> relevant interfaces. Application specific data can be added to the announce.</p>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
@@ -440,8 +461,8 @@ all interfaces. Application specific data can be added to the announce.</p>
</dd></dl> </dd></dl>
<dl class="py method"> <dl class="py method">
<dt class="sig sig-object py" id="RNS.Destination.link_established_callback"> <dt class="sig sig-object py" id="RNS.Destination.set_link_established_callback">
<span class="sig-name descname"><span class="pre">link_established_callback</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">callback</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.link_established_callback" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">set_link_established_callback</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">callback</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.set_link_established_callback" title="Permalink to this definition"></a></dt>
<dd><p>Registers a function to be called when a link has been established to <dd><p>Registers a function to be called when a link has been established to
this destination.</p> this destination.</p>
<dl class="field-list simple"> <dl class="field-list simple">
@@ -452,8 +473,8 @@ this destination.</p>
</dd></dl> </dd></dl>
<dl class="py method"> <dl class="py method">
<dt class="sig sig-object py" id="RNS.Destination.packet_callback"> <dt class="sig sig-object py" id="RNS.Destination.set_packet_callback">
<span class="sig-name descname"><span class="pre">packet_callback</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">callback</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.packet_callback" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">set_packet_callback</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">callback</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.set_packet_callback" title="Permalink to this definition"></a></dt>
<dd><p>Registers a function to be called when a packet has been received by <dd><p>Registers a function to be called when a packet has been received by
this destination.</p> this destination.</p>
<dl class="field-list simple"> <dl class="field-list simple">
@@ -464,8 +485,8 @@ this destination.</p>
</dd></dl> </dd></dl>
<dl class="py method"> <dl class="py method">
<dt class="sig sig-object py" id="RNS.Destination.proof_requested_callback"> <dt class="sig sig-object py" id="RNS.Destination.set_proof_requested_callback">
<span class="sig-name descname"><span class="pre">proof_requested_callback</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">callback</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.proof_requested_callback" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">set_proof_requested_callback</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">callback</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.set_proof_requested_callback" title="Permalink to this definition"></a></dt>
<dd><p>Registers a function to be called when a proof has been requested for <dd><p>Registers a function to be called when a proof has been requested for
a packet sent to this destination. Allows control over when and if a packet sent to this destination. Allows control over when and if
proofs should be returned for received packets.</p> proofs should be returned for received packets.</p>
@@ -592,8 +613,14 @@ unless other app_data is specified in the <em>announce</em> method.</p>
<dl class="py class"> <dl class="py class">
<dt class="sig sig-object py" id="RNS.Packet"> <dt class="sig sig-object py" id="RNS.Packet">
<em class="property"><span class="pre">class</span> </em><span class="sig-prename descclassname"><span class="pre">RNS.</span></span><span class="sig-name descname"><span class="pre">Packet</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">destination</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">data</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">packet_type</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">0</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">context</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">0</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">transport_type</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">0</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">header_type</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">0</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">transport_id</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">attached_interface</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">create_receipt</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Packet" title="Permalink to this definition"></a></dt> <em class="property"><span class="pre">class</span> </em><span class="sig-prename descclassname"><span class="pre">RNS.</span></span><span class="sig-name descname"><span class="pre">Packet</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">destination</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">data</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">packet_type</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">0</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">context</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">0</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">transport_type</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">0</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">header_type</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">0</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">transport_id</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">attached_interface</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">create_receipt</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Packet" title="Permalink to this definition"></a></dt>
<dd><p>The Packet class is used to create packet instances that can be <dd><p>The Packet class is used to create packet instances that can be sent
sent over a Reticulum network.</p> over a Reticulum network. Packets to will automatically be encrypted if
they are adressed to a <code class="docutils literal notranslate"><span class="pre">RNS.Destination.SINGLE</span></code> destination,
<code class="docutils literal notranslate"><span class="pre">RNS.Destination.GROUP</span></code> destination or a <a class="reference internal" href="#api-link"><span class="std std-ref">RNS.Link</span></a>.</p>
<p>For <code class="docutils literal notranslate"><span class="pre">RNS.Destination.GROUP</span></code> destinations, Reticulum will use the
pre-shared key configured for the destination.</p>
<p>For <code class="docutils literal notranslate"><span class="pre">RNS.Destination.SINGLE</span></code> destinations and <a class="reference internal" href="#api-link"><span class="std std-ref">RNS.Link</span></a>
destinations, reticulum will use ephemeral keys, and offers <strong>Forward Secrecy</strong>.</p>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple"> <dd class="field-odd"><ul class="simple">
@@ -608,6 +635,18 @@ sent over a Reticulum network.</p>
</ul> </ul>
</dd> </dd>
</dl> </dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="RNS.Packet.ENCRYPTED_MDU">
<span class="sig-name descname"><span class="pre">ENCRYPTED_MDU</span></span><em class="property"> <span class="pre">=</span> <span class="pre">383</span></em><a class="headerlink" href="#RNS.Packet.ENCRYPTED_MDU" title="Permalink to this definition"></a></dt>
<dd><p>The maximum size of the payload data in a single encrypted packet</p>
</dd></dl>
<dl class="py attribute">
<dt class="sig sig-object py" id="RNS.Packet.PLAIN_MDU">
<span class="sig-name descname"><span class="pre">PLAIN_MDU</span></span><em class="property"> <span class="pre">=</span> <span class="pre">477</span></em><a class="headerlink" href="#RNS.Packet.PLAIN_MDU" title="Permalink to this definition"></a></dt>
<dd><p>The maximum size of the payload data in a single unencrypted packet</p>
</dd></dl>
<dl class="py method"> <dl class="py method">
<dt class="sig sig-object py" id="RNS.Packet.send"> <dt class="sig sig-object py" id="RNS.Packet.send">
<span class="sig-name descname"><span class="pre">send</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Packet.send" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">send</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Packet.send" title="Permalink to this definition"></a></dt>
@@ -653,8 +692,8 @@ from a the <em>send()</em> method of a <a class="reference internal" href="#api-
</dd></dl> </dd></dl>
<dl class="py method"> <dl class="py method">
<dt class="sig sig-object py" id="RNS.PacketReceipt.rtt"> <dt class="sig sig-object py" id="RNS.PacketReceipt.get_rtt">
<span class="sig-name descname"><span class="pre">rtt</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#RNS.PacketReceipt.rtt" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">get_rtt</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#RNS.PacketReceipt.get_rtt" title="Permalink to this definition"></a></dt>
<dd><dl class="field-list simple"> <dd><dl class="field-list simple">
<dt class="field-odd">Returns</dt> <dt class="field-odd">Returns</dt>
<dd class="field-odd"><p>The round-trip-time in seconds</p> <dd class="field-odd"><p>The round-trip-time in seconds</p>
@@ -674,8 +713,8 @@ from a the <em>send()</em> method of a <a class="reference internal" href="#api-
</dd></dl> </dd></dl>
<dl class="py method"> <dl class="py method">
<dt class="sig sig-object py" id="RNS.PacketReceipt.delivery_callback"> <dt class="sig sig-object py" id="RNS.PacketReceipt.set_delivery_callback">
<span class="sig-name descname"><span class="pre">delivery_callback</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">callback</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.PacketReceipt.delivery_callback" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">set_delivery_callback</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">callback</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.PacketReceipt.set_delivery_callback" title="Permalink to this definition"></a></dt>
<dd><p>Sets a function that gets called if a successfull delivery has been proven.</p> <dd><p>Sets a function that gets called if a successfull delivery has been proven.</p>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters</dt>
@@ -685,8 +724,8 @@ from a the <em>send()</em> method of a <a class="reference internal" href="#api-
</dd></dl> </dd></dl>
<dl class="py method"> <dl class="py method">
<dt class="sig sig-object py" id="RNS.PacketReceipt.timeout_callback"> <dt class="sig sig-object py" id="RNS.PacketReceipt.set_timeout_callback">
<span class="sig-name descname"><span class="pre">timeout_callback</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">callback</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.PacketReceipt.timeout_callback" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">set_timeout_callback</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">callback</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.PacketReceipt.set_timeout_callback" title="Permalink to this definition"></a></dt>
<dd><p>Sets a function that gets called if the delivery times out.</p> <dd><p>Sets a function that gets called if the delivery times out.</p>
<dl class="field-list simple"> <dl class="field-list simple">
<dt class="field-odd">Parameters</dt> <dt class="field-odd">Parameters</dt>
@@ -728,7 +767,7 @@ from a the <em>send()</em> method of a <a class="reference internal" href="#api-
<dl class="py attribute"> <dl class="py attribute">
<dt class="sig sig-object py" id="RNS.Link.KEEPALIVE"> <dt class="sig sig-object py" id="RNS.Link.KEEPALIVE">
<span class="sig-name descname"><span class="pre">KEEPALIVE</span></span><em class="property"> <span class="pre">=</span> <span class="pre">180</span></em><a class="headerlink" href="#RNS.Link.KEEPALIVE" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">KEEPALIVE</span></span><em class="property"> <span class="pre">=</span> <span class="pre">360</span></em><a class="headerlink" href="#RNS.Link.KEEPALIVE" title="Permalink to this definition"></a></dt>
<dd><p>Interval for sending keep-alive packets on established links in seconds.</p> <dd><p>Interval for sending keep-alive packets on established links in seconds.</p>
</dd></dl> </dd></dl>
@@ -770,8 +809,8 @@ be used if a new link to the same destination is established.</p>
</dd></dl> </dd></dl>
<dl class="py method"> <dl class="py method">
<dt class="sig sig-object py" id="RNS.Link.packet_callback"> <dt class="sig sig-object py" id="RNS.Link.set_packet_callback">
<span class="sig-name descname"><span class="pre">packet_callback</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">callback</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Link.packet_callback" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">set_packet_callback</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">callback</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Link.set_packet_callback" title="Permalink to this definition"></a></dt>
<dd><p>Registers a function to be called when a packet has been <dd><p>Registers a function to be called when a packet has been
received over this link.</p> received over this link.</p>
<dl class="field-list simple"> <dl class="field-list simple">
@@ -782,8 +821,8 @@ received over this link.</p>
</dd></dl> </dd></dl>
<dl class="py method"> <dl class="py method">
<dt class="sig sig-object py" id="RNS.Link.resource_callback"> <dt class="sig sig-object py" id="RNS.Link.set_resource_callback">
<span class="sig-name descname"><span class="pre">resource_callback</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">callback</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Link.resource_callback" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">set_resource_callback</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">callback</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Link.set_resource_callback" title="Permalink to this definition"></a></dt>
<dd><p>Registers a function to be called when a resource has been <dd><p>Registers a function to be called when a resource has been
advertised over this link. If the function returns <em>True</em> advertised over this link. If the function returns <em>True</em>
the resource will be accepted. If it returns <em>False</em> it will the resource will be accepted. If it returns <em>False</em> it will
@@ -796,8 +835,8 @@ be ignored.</p>
</dd></dl> </dd></dl>
<dl class="py method"> <dl class="py method">
<dt class="sig sig-object py" id="RNS.Link.resource_started_callback"> <dt class="sig sig-object py" id="RNS.Link.set_resource_started_callback">
<span class="sig-name descname"><span class="pre">resource_started_callback</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">callback</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Link.resource_started_callback" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">set_resource_started_callback</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">callback</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Link.set_resource_started_callback" title="Permalink to this definition"></a></dt>
<dd><p>Registers a function to be called when a resource has begun <dd><p>Registers a function to be called when a resource has begun
transferring over this link.</p> transferring over this link.</p>
<dl class="field-list simple"> <dl class="field-list simple">
@@ -808,8 +847,8 @@ transferring over this link.</p>
</dd></dl> </dd></dl>
<dl class="py method"> <dl class="py method">
<dt class="sig sig-object py" id="RNS.Link.resource_concluded_callback"> <dt class="sig sig-object py" id="RNS.Link.set_resource_concluded_callback">
<span class="sig-name descname"><span class="pre">resource_concluded_callback</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">callback</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Link.resource_concluded_callback" title="Permalink to this definition"></a></dt> <span class="sig-name descname"><span class="pre">set_resource_concluded_callback</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">callback</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Link.set_resource_concluded_callback" title="Permalink to this definition"></a></dt>
<dd><p>Registers a function to be called when a resource has concluded <dd><p>Registers a function to be called when a resource has concluded
transferring over this link.</p> transferring over this link.</p>
<dl class="field-list simple"> <dl class="field-list simple">
@@ -852,7 +891,7 @@ client application and throw an error message to the user.</p>
<span id="api-resource"></span><h3>Resource<a class="headerlink" href="#resource" title="Permalink to this headline"></a></h3> <span id="api-resource"></span><h3>Resource<a class="headerlink" href="#resource" title="Permalink to this headline"></a></h3>
<dl class="py class"> <dl class="py class">
<dt class="sig sig-object py" id="RNS.Resource"> <dt class="sig sig-object py" id="RNS.Resource">
<em class="property"><span class="pre">class</span> </em><span class="sig-prename descclassname"><span class="pre">RNS.</span></span><span class="sig-name descname"><span class="pre">Resource</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">data</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">link</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">advertise</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">auto_compress</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">must_compress</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">callback</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">progress_callback</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">segment_index</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">1</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">original_hash</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Resource" title="Permalink to this definition"></a></dt> <em class="property"><span class="pre">class</span> </em><span class="sig-prename descclassname"><span class="pre">RNS.</span></span><span class="sig-name descname"><span class="pre">Resource</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">data</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">link</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">advertise</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">auto_compress</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">callback</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">progress_callback</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">segment_index</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">1</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">original_hash</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Resource" title="Permalink to this definition"></a></dt>
<dd><p>The Resource class allows transferring arbitrary amounts <dd><p>The Resource class allows transferring arbitrary amounts
of data over a link. It will automatically handle sequencing, of data over a link. It will automatically handle sequencing,
compression, coordination and checksumming.</p> compression, coordination and checksumming.</p>
@@ -863,7 +902,6 @@ compression, coordination and checksumming.</p>
<li><p><strong>link</strong> The <a class="reference internal" href="#api-link"><span class="std std-ref">RNS.Link</span></a> instance on which to transfer the data.</p></li> <li><p><strong>link</strong> The <a class="reference internal" href="#api-link"><span class="std std-ref">RNS.Link</span></a> instance on which to transfer the data.</p></li>
<li><p><strong>advertise</strong> Whether to automatically advertise the resource. Can be <em>True</em> or <em>False</em>.</p></li> <li><p><strong>advertise</strong> Whether to automatically advertise the resource. Can be <em>True</em> or <em>False</em>.</p></li>
<li><p><strong>auto_compress</strong> Whether to auto-compress the resource. Can be <em>True</em> or <em>False</em>.</p></li> <li><p><strong>auto_compress</strong> Whether to auto-compress the resource. Can be <em>True</em> or <em>False</em>.</p></li>
<li><p><strong>auto_compress</strong> Whether the resource must be compressed. Can be <em>True</em> or <em>False</em>. Used for debugging, will disappear in the future.</p></li>
<li><p><strong>callback</strong> A <em>callable</em> with the signature <em>callback(resource)</em>. Will be called when the resource transfer concludes.</p></li> <li><p><strong>callback</strong> A <em>callable</em> with the signature <em>callback(resource)</em>. Will be called when the resource transfer concludes.</p></li>
<li><p><strong>progress_callback</strong> A <em>callable</em> with the signature <em>callback(resource)</em>. Will be called whenever the resource transfer progress is updated.</p></li> <li><p><strong>progress_callback</strong> A <em>callable</em> with the signature <em>callback(resource)</em>. Will be called whenever the resource transfer progress is updated.</p></li>
<li><p><strong>segment_index</strong> Internal use, ignore.</p></li> <li><p><strong>segment_index</strong> Internal use, ignore.</p></li>
@@ -982,11 +1020,11 @@ will announce it.</p>
</ul> </ul>
<h4>Previous topic</h4> <h4>Previous topic</h4>
<p class="topless"><a href="examples.html"
title="previous chapter">Examples</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="understanding.html" <p class="topless"><a href="understanding.html"
title="next chapter">Understanding Reticulum</a></p> title="previous chapter">Understanding Reticulum</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="examples.html"
title="next chapter">Examples</a></p>
<div role="note" aria-label="source link"> <div role="note" aria-label="source link">
<h3>This Page</h3> <h3>This Page</h3>
<ul class="this-page-menu"> <ul class="this-page-menu">
@@ -1015,12 +1053,12 @@ will announce it.</p>
<a href="genindex.html" title="General Index" <a href="genindex.html" title="General Index"
>index</a></li> >index</a></li>
<li class="right" > <li class="right" >
<a href="understanding.html" title="Understanding Reticulum" <a href="examples.html" title="Examples"
>next</a> |</li> >next</a> |</li>
<li class="right" > <li class="right" >
<a href="examples.html" title="Examples" <a href="understanding.html" title="Understanding Reticulum"
>previous</a> |</li> >previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.0 beta documentation</a> &#187;</li> <li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">API Reference</a></li> <li class="nav-item nav-item-this"><a href="">API Reference</a></li>
</ul> </ul>
</div> </div>
+3 -3
View File
@@ -5,7 +5,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Search &#8212; Reticulum Network Stack 0.2.0 beta documentation</title> <title>Search &#8212; Reticulum Network Stack 0.2.1 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" /> <link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -29,7 +29,7 @@
<li class="right" style="margin-right: 10px"> <li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index" <a href="genindex.html" title="General Index"
accesskey="I">index</a></li> accesskey="I">index</a></li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.0 beta documentation</a> &#187;</li> <li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Search</a></li> <li class="nav-item nav-item-this"><a href="">Search</a></li>
</ul> </ul>
</div> </div>
@@ -85,7 +85,7 @@
<li class="right" style="margin-right: 10px"> <li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index" <a href="genindex.html" title="General Index"
>index</a></li> >index</a></li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.0 beta documentation</a> &#187;</li> <li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Search</a></li> <li class="nav-item nav-item-this"><a href="">Search</a></li>
</ul> </ul>
</div> </div>
File diff suppressed because one or more lines are too long
+169 -108
View File
@@ -5,7 +5,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Understanding Reticulum &#8212; Reticulum Network Stack 0.2.0 beta documentation</title> <title>Understanding Reticulum &#8212; Reticulum Network Stack 0.2.1 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" /> <link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -16,7 +16,8 @@
<link rel="index" title="Index" href="genindex.html" /> <link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" /> <link rel="search" title="Search" href="search.html" />
<link rel="prev" title="API Reference" href="reference.html" /> <link rel="next" title="API Reference" href="reference.html" />
<link rel="prev" title="Getting Started Fast" href="gettingstartedfast.html" />
</head><body> </head><body>
<div class="related" role="navigation" aria-label="related navigation"> <div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3> <h3>Navigation</h3>
@@ -26,8 +27,11 @@
accesskey="I">index</a></li> accesskey="I">index</a></li>
<li class="right" > <li class="right" >
<a href="reference.html" title="API Reference" <a href="reference.html" title="API Reference"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="gettingstartedfast.html" title="Getting Started Fast"
accesskey="P">previous</a> |</li> accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.0 beta documentation</a> &#187;</li> <li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Understanding Reticulum</a></li> <li class="nav-item nav-item-this"><a href="">Understanding Reticulum</a></li>
</ul> </ul>
</div> </div>
@@ -201,12 +205,14 @@ when a node is directly reachable.</p>
</ul> </ul>
<div class="section" id="destination-naming"> <div class="section" id="destination-naming">
<span id="understanding-destinationnaming"></span><h4>Destination Naming<a class="headerlink" href="#destination-naming" title="Permalink to this headline"></a></h4> <span id="understanding-destinationnaming"></span><h4>Destination Naming<a class="headerlink" href="#destination-naming" title="Permalink to this headline"></a></h4>
<p>Destinations are created and named in an easy to understand dotted notation of <em>aspects</em> , and <p>Destinations are created and named in an easy to understand dotted notation of <em>aspects</em>, and
represented on the network as a hash of this value. The hash is a SHA-256 truncated to 80 bits. The represented on the network as a hash of this value. The hash is a SHA-256 truncated to 80 bits. The
top level aspect should always be a unique identifier for the application using the destination. top level aspect should always be a unique identifier for the application using the destination.
The next levels of aspects can be defined in any way by the creator of the application. For example, The next levels of aspects can be defined in any way by the creator of the application.</p>
a destination for a environmental monitoring application could be made up of the application name, a <p>Aspects can be as long and as plentiful as required, and a resulting long destination name will not
device type and measurement type, like this:</p> impact efficiency, as names are always represented as truncated SHA-256 hashes on the network.</p>
<p>As an example, a destination for a environmental monitoring application could be made up of the
application name, a device type and measurement type, like this:</p>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>app name : environmentlogger <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>app name : environmentlogger
aspects : remotesensor, temperature aspects : remotesensor, temperature
@@ -242,9 +248,8 @@ receives.</p>
</dl> </dl>
</li> </li>
<li><dl class="simple"> <li><dl class="simple">
<dt><strong>Group</strong></dt><dd><p>When private communication between two or more endpoints is needed. More efficient in <dt><strong>Group</strong></dt><dd><p>When private communication between two or more endpoints is needed. Supports multiple hops
data usage than <em>single</em> destinations. Supports multiple hops indirectly, but must first be indirectly, but must first be established through a <em>single</em> destination.</p>
established through a <em>single</em> destination.</p>
</dd> </dd>
</dl> </dl>
</li> </li>
@@ -260,9 +265,9 @@ nodes aware of your destinations public key, called the <em>announce</em>. It is
an unknown public key from the network, as all participating nodes serve as a distributed ledger an unknown public key from the network, as all participating nodes serve as a distributed ledger
of public keys.</p> of public keys.</p>
<p>Note that public key information can be shared and verified in many other ways than using the <p>Note that public key information can be shared and verified in many other ways than using the
built-in methodology, and that it is therefore not required to use the announce/request functionality. built-in <em>announce</em> functionality, and that it is therefore not required to use the announce/request
It is by far the easiest though, and should definitely be used if there is not a good reason for functionality to obtain public keys. It is by far the easiest though, and should definitely be used
doing it differently.</p> if there is not a good reason for doing it differently.</p>
</div> </div>
</div> </div>
<div class="section" id="public-key-announcements"> <div class="section" id="public-key-announcements">
@@ -278,7 +283,7 @@ contain the following information:</p>
<li><p>The announcers public key</p></li> <li><p>The announcers public key</p></li>
<li><p>Application specific data, in this case the users nickname and availability status</p></li> <li><p>Application specific data, in this case the users nickname and availability status</p></li>
<li><p>A random blob, making each new announce unique</p></li> <li><p>A random blob, making each new announce unique</p></li>
<li><p>A signature of the above information, verifying authenticity</p></li> <li><p>An Ed25519 signature of the above information, verifying authenticity</p></li>
</ul> </ul>
<p>With this information, any Reticulum node that receives it will be able to reconstruct an outgoing <p>With this information, any Reticulum node that receives it will be able to reconstruct an outgoing
destination to securely communicate with that destination. You might have noticed that there is one destination to securely communicate with that destination. You might have noticed that there is one
@@ -286,8 +291,9 @@ piece of information lacking to reconstruct full knowledge of the announced dest
the aspect names of the destination. These are intentionally left out to save bandwidth, since they the aspect names of the destination. These are intentionally left out to save bandwidth, since they
will be implicit in almost all cases. If a destination name is not entirely implicit, information can be will be implicit in almost all cases. If a destination name is not entirely implicit, information can be
included in the application specific data part that will allow the receiver to infer the naming.</p> included in the application specific data part that will allow the receiver to infer the naming.</p>
<p>It is important to note that announcements will be forwarded throughout the network according to a <p>It is important to note that announces will be forwarded throughout the network according to a
certain pattern. This will be detailed later.</p> certain pattern. This will be detailed in the section
<a class="reference internal" href="#understanding-announce"><span class="std std-ref">The Announce Mechanism in Detail</span></a>.</p>
<p>Seeing how <em>single</em> destinations are always tied to a private/public key pair leads us to the next topic.</p> <p>Seeing how <em>single</em> destinations are always tied to a private/public key pair leads us to the next topic.</p>
</div> </div>
<div class="section" id="understanding-identities"> <div class="section" id="understanding-identities">
@@ -304,16 +310,16 @@ automatically. This may be desirable in some situations, but often you will prob
the identity first, and then link it to created destinations.</p> the identity first, and then link it to created destinations.</p>
<p>Building upon the simple messenger example, we could use an identity to represent the user of the <p>Building upon the simple messenger example, we could use an identity to represent the user of the
application. Destinations created will then be linked to this identity to allow communication to application. Destinations created will then be linked to this identity to allow communication to
reach the user. In such a case it is of great importance to store the users identity securely and reach the user. In all cases it is of great importance to store the private keys associated with any
privately.</p> Reticulum Identity securely and privately.</p>
</div> </div>
<div class="section" id="getting-further"> <div class="section" id="getting-further">
<span id="understanding-gettingfurther"></span><h3>Getting Further<a class="headerlink" href="#getting-further" title="Permalink to this headline"></a></h3> <span id="understanding-gettingfurther"></span><h3>Getting Further<a class="headerlink" href="#getting-further" title="Permalink to this headline"></a></h3>
<p>The above functions and principles form the core of Reticulum, and would suffice to create <p>The above functions and principles form the core of Reticulum, and would suffice to create
functional networked applications in local clusters, for example over radio links where all interested functional networked applications in local clusters, for example over radio links where all interested
nodes can directly hear each other. But to be truly useful, we need a way to direct traffic over multiple nodes can directly hear each other. But to be truly useful, we need a way to direct traffic over multiple
hops in the network. In the next sections, two concepts that allow this will be introduced, <em>paths</em> and hops in the network.</p>
<em>links</em>.</p> <p>In the following sections, two concepts that allow this will be introduced, <em>paths</em> and <em>links</em>.</p>
</div> </div>
</div> </div>
<div class="section" id="reticulum-transport"> <div class="section" id="reticulum-transport">
@@ -327,69 +333,20 @@ very limited. Existing routing protocols like BGP or OSPF carry too much overhea
useable over bandwidth-limited, high-latency links.</p> useable over bandwidth-limited, high-latency links.</p>
<p>To overcome such challenges, Reticulums <em>Transport</em> system uses public-key cryptography to <p>To overcome such challenges, Reticulums <em>Transport</em> system uses public-key cryptography to
implement the concept of <em>paths</em> that allow discovery of how to get information to a certain implement the concept of <em>paths</em> that allow discovery of how to get information to a certain
destination, and <em>resources</em> that help make reliable data transfer more efficient.</p> destination. It is important to note that no single node in a Reticulum network knows the complete
<div class="section" id="reaching-the-destination"> path to a destination. Every Transport node participating in a Reticulum network will only
<span id="understanding-paths"></span><h3>Reaching the Destination<a class="headerlink" href="#reaching-the-destination" title="Permalink to this headline"></a></h3> know what the most direct way to get a packet one hop closer to its destination is.</p>
<p>In networks with changing topology and trustless connectivity, nodes need a way to establish <div class="section" id="the-announce-mechanism-in-detail">
<em>verified connectivity</em> with each other. Since the network is assumed to be trustless, Reticulum <span id="understanding-announce"></span><h3>The Announce Mechanism in Detail<a class="headerlink" href="#the-announce-mechanism-in-detail" title="Permalink to this headline"></a></h3>
must provide a way to guarantee that the peer you are communicating with is actually who you <p>When an <em>announce</em> is transmitted by a node, it will be forwarded by any node receiving it, but
expect. To do this, the following process is employed:</p> according to some specific rules:</p>
<ul> <ul>
<li><div class="line-block"> <li><div class="line-block">
<div class="line">First, the node that wishes to establish connectivity will send out a special packet, that <div class="line">If this exact announce has already been received before, ignore it.</div>
traverses the network and locates the desired destination. Along the way, the nodes that
forward the packet will take note of this <em>link request</em>.</div>
</div> </div>
</li> </li>
<li><div class="line-block"> <li><div class="line-block">
<div class="line">Second, if the destination accepts the <em>link request</em> , it will send back a packet that proves the <div class="line">If not, record into a table which node the announce was received from, and how many times in
authenticity of its identity (and the receipt of the link request) to the initiating node. All
nodes that initially forwarded the packet will also be able to verify this proof, and thus
accept the validity of the <em>link</em> throughout the network.</div>
</div>
</li>
<li><div class="line-block">
<div class="line">When the validity of the <em>link</em> has been accepted by forwarding nodes, these nodes will
remember the <em>link</em> , and it can subsequently be used by referring to a hash representing it.</div>
</div>
</li>
<li><div class="line-block">
<div class="line">As a part of the <em>link request</em> , a Diffie-Hellman key exchange takes place, that sets up an
efficient symmetrically encrypted tunnel between the two nodes, using elliptic curve
cryptography. As such, this mode of communication is preferred, even for situations when
nodes can directly communicate, when the amount of data to be exchanged numbers in the
tens of packets.</div>
</div>
</li>
<li><div class="line-block">
<div class="line">When a <em>link</em> has been set up, it automatically provides message receipt functionality, so the
sending node can obtain verified confirmation that the information reached the intended
recipient.</div>
</div>
</li>
</ul>
<p>In a moment, we will discuss the specifics of how this methodology is implemented, but lets first
recap what purposes this serves. We first ensure that the node answering our request is actually the
one we want to communicate with, and not a malicious actor pretending to be so. At the same time
we establish an efficient encrypted channel. The setup of this is relatively cheap in terms of
bandwidth, so it can be used just for a short exchange, and then recreated as needed, which will also
rotate encryption keys, but the link can also be kept alive for longer periods of time, if this is
more suitable to the application. The amount of bandwidth used on keeping a link open is practically
negligible. The procedure also inserts the <em>link id</em> , a hash calculated from the link request packet,
into the memory of forwarding nodes, which means that the communicating nodes can thereafter reach each
other simply by referring to this <em>link id</em>.</p>
<div class="section" id="step-1-pathfinding">
<h4>Step 1: Pathfinding<a class="headerlink" href="#step-1-pathfinding" title="Permalink to this headline"></a></h4>
<p>The pathfinding method builds on the <em>announce</em> functionality discussed earlier. When an announce
is sent out by a node, it will be forwarded by any node receiving it, but according to some specific
rules:</p>
<ul>
<li><div class="line-block">
<div class="line">If this announce has already been received before, ignore it.</div>
</div>
</li>
<li><div class="line-block">
<div class="line">Record into a table which node the announce was received from, and how many times in
total it has been retransmitted to get here.</div> total it has been retransmitted to get here.</div>
</div> </div>
</li> </li>
@@ -399,8 +356,7 @@ set to 18.</div>
</div> </div>
</li> </li>
<li><div class="line-block"> <li><div class="line-block">
<div class="line">The announce will be assigned a delay <em>d</em> = c<sup>h</sup> seconds, where <em>c</em> is a decay constant, by <div class="line">The announce will be assigned a delay <em>d</em> = c<sup>h</sup> seconds, where <em>c</em> is a decay constant, and <em>h</em> is the amount of times this packet has already been forwarded.</div>
default 2, and <em>h</em> is the amount of times this packet has already been forwarded.</div>
</div> </div>
</li> </li>
<li><div class="line-block"> <li><div class="line-block">
@@ -415,10 +371,11 @@ not utilized by other traffic, the announce will be forwarded.</div>
</li> </li>
<li><div class="line-block"> <li><div class="line-block">
<div class="line">If no other nodes are heard retransmitting the announce with a greater hop count than when <div class="line">If no other nodes are heard retransmitting the announce with a greater hop count than when
it left this node, transmitting it will be retried <em>r</em> times. By default, <em>r</em> is set to 2. Retries follow it left this node, transmitting it will be retried <em>r</em> times. By default, <em>r</em> is set to 1. Retries
same rules as above, with the exception that it must wait for at least <em>d</em> = c<sup>h+1</sup> + t seconds, ie., follow same rules as above, with the exception that it must wait for at least <em>d</em> = c<sup>h+1</sup> +
the amount of time it would take the next node to retransmit the packet. By default, <em>t</em> is set to t + rand(0, rw) seconds. This amount of time is equal to the amount of time it would take the next
10.</div> node to retransmit the packet, plus a random window. By default, <em>t</em> is set to 10 seconds, and the
random window <em>rw</em> is set to 10 seconds.</div>
</div> </div>
</li> </li>
<li><div class="line-block"> <li><div class="line-block">
@@ -440,13 +397,111 @@ distance of <em>Lavg =</em> 15 kilometers, an announce will be able to propagate
kilometers in 34 minutes, and a <em>maximum announce radius</em> of 270 kilometers in approximately 3 kilometers in 34 minutes, and a <em>maximum announce radius</em> of 270 kilometers in approximately 3
days.</p> days.</p>
</div> </div>
<div class="section" id="step-2-link-establishment"> <div class="section" id="reaching-the-destination">
<h4>Step 2: Link Establishment<a class="headerlink" href="#step-2-link-establishment" title="Permalink to this headline"></a></h4> <span id="understanding-paths"></span><h3>Reaching the Destination<a class="headerlink" href="#reaching-the-destination" title="Permalink to this headline"></a></h3>
<p>After seeing how the conditions for finding a path through the network are created, we will now <p>In networks with changing topology and trustless connectivity, nodes need a way to establish
explore how two nodes can establish reliable communications over multiple hops. The <em>link</em> in <em>verified connectivity</em> with each other. Since the network is assumed to be trustless, Reticulum
Reticulum terminology should not be viewed as a direct node-to-node link on the physical layer, but must provide a way to guarantee that the peer you are communicating with is actually who you
as an abstract channel, that can be open for any amount of time, and can span an arbitrary number expect. Reticulum offers two ways to do this.</p>
of hops, where information will be exchanged between two nodes.</p> <p>For exchanges of small amounts of information, Reticulum offers the <em>Packet</em> API, which works exactly like you would expect - on a per packet level. The following process is employed when sending a packet:</p>
<ul>
<li><div class="line-block">
<div class="line">A packet is always created with an associated destination and some payload data. When the packet is sent
to a <em>single</em> destination type, Reticulum will automatically create an ephemeral encryption key, perform
an ECDH key exchange with the destinations public key, and encrypt the information.</div>
</div>
</li>
<li><div class="line-block">
<div class="line">It is important to note that this key exchange does not require any network traffic. The sender already
knows the public key of the destination from an earlier received <em>announce</em>, and can thus perform the ECDH
key exchange locally, before sending the packet.</div>
</div>
</li>
<li><div class="line-block">
<div class="line">The public part of the newly generated ephemeral key-pair is included with the encrypted token, and sent
along with the encrypted payload data in the packet.</div>
</div>
</li>
<li><div class="line-block">
<div class="line">When the destination receives the packet, it can itself perform an ECDH key exchange and decrypt the
packet.</div>
</div>
</li>
<li><div class="line-block">
<div class="line">A new ephemeral key is used for every packet sent in this way, and forward secrecy is guaranteed on a
per packet level.</div>
</div>
</li>
<li><div class="line-block">
<div class="line">Once the packet has been received and decrypted by the addressed destination, that destination can opt
to <em>prove</em> its receipt of the packet. It does this by calculating the SHA-256 hash of the received packet,
and signing this hash with its Ed25519 signing key. Transport nodes in the network can then direct this
<em>proof</em> back to the packets origin, where the signature can be verified against the destinations known
public signing key.</div>
</div>
</li>
<li><div class="line-block">
<div class="line">In case the packet is addressed to a <em>group</em> destination type, the packet will be encrypted with the
pre-shared AES-128 key associated with the destination. In case the packet is addressed to a <em>plain</em>
destination type, the payload data will not be encrypted. Neither of these two destination types offer
forward secrecy. In general, it is recommended to always use the <em>single</em> destination type, unless it is
strictly necessary to use one of the others.</div>
</div>
</li>
</ul>
<p>For exchanges of larger amounts of data, or when longer sessions of bidirectional communication is desired, Reticulum offers the <em>Link</em> API. To establish a <em>link</em>, the following process is employed:</p>
<ul>
<li><div class="line-block">
<div class="line">First, the node that wishes to establish a link will send out a special packet, that
traverses the network and locates the desired destination. Along the way, the nodes that
forward the packet will take note of this <em>link request</em>.</div>
</div>
</li>
<li><div class="line-block">
<div class="line">Second, if the destination accepts the <em>link request</em> , it will send back a packet that proves the
authenticity of its identity (and the receipt of the link request) to the initiating node. All
nodes that initially forwarded the packet will also be able to verify this proof, and thus
accept the validity of the <em>link</em> throughout the network.</div>
</div>
</li>
<li><div class="line-block">
<div class="line">When the validity of the <em>link</em> has been accepted by forwarding nodes, these nodes will
remember the <em>link</em> , and it can subsequently be used by referring to a hash representing it.</div>
</div>
</li>
<li><div class="line-block">
<div class="line">As a part of the <em>link request</em> , a Diffie-Hellman key exchange takes place, that sets up an
efficiently encrypted tunnel between the two nodes, using elliptic curve cryptography. As such,
this mode of communication is preferred, even for situations when nodes can directly communicate,
when the amount of data to be exchanged numbers in the tens of packets.</div>
</div>
</li>
<li><div class="line-block">
<div class="line">When a <em>link</em> has been set up, it automatically provides message receipt functionality, through
the same <em>proof</em> mechanism discussed before, so the sending node can obtain verified confirmation
that the information reached the intended recipient.</div>
</div>
</li>
</ul>
<p>In a moment, we will discuss the details of how this methodology is implemented, but lets first
recap what purposes this methodology serves. We first ensure that the node answering our request
is actually the one we want to communicate with, and not a malicious actor pretending to be so.
At the same time we establish an efficient encrypted channel. The setup of this is relatively cheap in
terms of bandwidth, so it can be used just for a short exchange, and then recreated as needed, which will
also rotate encryption keys. The link can also be kept alive for longer periods of time, if this is
more suitable to the application. The procedure also inserts the <em>link id</em> , a hash calculated from the link request packet, into the memory of forwarding nodes, which means that the communicating nodes can thereafter reach each other simply by referring to this <em>link id</em>.</p>
<p>The combined bandwidth cost of setting up a link is 3 packets totalling 240 bytes (more info in the
<a class="reference internal" href="#understanding-packetformat"><span class="std std-ref">Binary Packet Format</span></a> section). The amount of bandwidth used on keeping
a link open is practically negligible, at 0.62 bits per second. Even on a slow 1200 bits per second packet
radio channel, 100 concurrent links will still leave 95% channel capacity for actual data.</p>
<div class="section" id="link-establishment-in-detail">
<h4>Link Establishment in Detail<a class="headerlink" href="#link-establishment-in-detail" title="Permalink to this headline"></a></h4>
<p>After exploring the basics of the announce mechanism, finding a path through the network, and an overview
of the link establishment procedure, this section will go into greater detail about the Reticulum link
establishment process.</p>
<p>The <em>link</em> in Reticulum terminology should not be viewed as a direct node-to-node link on the
physical layer, but as an abstract channel, that can be open for any amount of time, and can span
an arbitrary number of hops, where information will be exchanged between two nodes.</p>
<ul> <ul>
<li><div class="line-block"> <li><div class="line-block">
<div class="line">When a node in the network wants to establish verified connectivity with another node, it <div class="line">When a node in the network wants to establish verified connectivity with another node, it
@@ -461,8 +516,7 @@ considered as single public key for simplicity in this explanation.</em></div>
</li> </li>
<li><div class="line-block"> <li><div class="line-block">
<div class="line">The <em>link request</em> is addressed to the destination hash of the desired destination, and <div class="line">The <em>link request</em> is addressed to the destination hash of the desired destination, and
contains the following data: The newly generated X25519 public key <em>LKi</em>. The contents contains the following data: The newly generated X25519 public key <em>LKi</em>.</div>
are encrypted with the RSA public key of the destination and tramsitted over the network.</div>
</div> </div>
</li> </li>
<li><div class="line-block"> <li><div class="line-block">
@@ -473,21 +527,22 @@ previously.</div>
<li><div class="line-block"> <li><div class="line-block">
<div class="line">Any node that forwards the link request will store a <em>link id</em> in its <em>link table</em> , along with the <div class="line">Any node that forwards the link request will store a <em>link id</em> in its <em>link table</em> , along with the
amount of hops the packet had taken when received. The link id is a hash of the entire link amount of hops the packet had taken when received. The link id is a hash of the entire link
request packet. If the path is not <em>proven</em> within some set amount of time, the entry will be request packet. If the link request packet is not <em>proven</em> by the addressed destination within some
dropped from the <em>link table</em> again.</div> set amount of time, the entry will be dropped from the <em>link table</em> again.</div>
</div> </div>
</li> </li>
<li><div class="line-block"> <li><div class="line-block">
<div class="line">When the destination receives the link request packet, it will decrypt it and decide whether to <div class="line">When the destination receives the link request packet, it will decide whether to accept the request.
accept the request. If it is accepted, the destination will also generate a new X25519 private/public If it is accepted, the destination will also generate a new X25519 private/public key pair, and
key pair, and perform a Diffie Hellman Key Exchange, deriving a new symmetric key that will be used perform a Diffie Hellman Key Exchange, deriving a new symmetric key that will be used to encrypt the
to encrypt the channel, once it has been established.</div> channel, once it has been established.</div>
</div> </div>
</li> </li>
<li><div class="line-block"> <li><div class="line-block">
<div class="line">A <em>link proof</em> packet is now constructed and transmitted over the network. This packet is <div class="line">A <em>link proof</em> packet is now constructed and transmitted over the network. This packet is
addressed to the <em>link id</em> of the <em>link</em>. It contains the following data: The newly generated X25519 addressed to the <em>link id</em> of the <em>link</em>. It contains the following data: The newly generated X25519
public key <em>LKr</em> and an RSA-1024 signature of the <em>link id</em> and <em>LKr</em>.</div> public key <em>LKr</em> and an Ed25519 signature of the <em>link id</em> and <em>LKr</em> made by the signing key of
the addressed destination.</div>
</div> </div>
</li> </li>
<li><div class="line-block"> <li><div class="line-block">
@@ -615,7 +670,7 @@ the light of Reticulums goal of equal access, doing so would need to be the subj
investigation of the consequences first.</p> investigation of the consequences first.</p>
</div> </div>
<div class="section" id="binary-packet-format"> <div class="section" id="binary-packet-format">
<h3>Binary Packet Format<a class="headerlink" href="#binary-packet-format" title="Permalink to this headline"></a></h3> <span id="understanding-packetformat"></span><h3>Binary Packet Format<a class="headerlink" href="#binary-packet-format" title="Permalink to this headline"></a></h3>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>== Reticulum Wire Format ====== <div class="highlight-text notranslate"><div class="highlight"><pre><span></span>== Reticulum Wire Format ======
A Reticulum packet is composed of the following fields: A Reticulum packet is composed of the following fields:
@@ -706,9 +761,9 @@ proof 11
wire size including all fields. wire size including all fields.
- Path Request : 33 bytes - Path Request : 33 bytes
- Announce : 323 bytes - Announce : 151 bytes
- Link Request : 141 bytes - Link Request : 77 bytes
- Link Proof : 205 bytes - Link Proof : 77 bytes
- Link RTT packet : 86 bytes - Link RTT packet : 86 bytes
- Link keepalive : 14 bytes - Link keepalive : 14 bytes
</pre></div> </pre></div>
@@ -740,9 +795,9 @@ proof 11
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#reticulum-transport">Reticulum Transport</a><ul> <li><a class="reference internal" href="#reticulum-transport">Reticulum Transport</a><ul>
<li><a class="reference internal" href="#the-announce-mechanism-in-detail">The Announce Mechanism in Detail</a></li>
<li><a class="reference internal" href="#reaching-the-destination">Reaching the Destination</a><ul> <li><a class="reference internal" href="#reaching-the-destination">Reaching the Destination</a><ul>
<li><a class="reference internal" href="#step-1-pathfinding">Step 1: Pathfinding</a></li> <li><a class="reference internal" href="#link-establishment-in-detail">Link Establishment in Detail</a></li>
<li><a class="reference internal" href="#step-2-link-establishment">Step 2: Link Establishment</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference internal" href="#resources">Resources</a></li> <li><a class="reference internal" href="#resources">Resources</a></li>
@@ -760,8 +815,11 @@ proof 11
</ul> </ul>
<h4>Previous topic</h4> <h4>Previous topic</h4>
<p class="topless"><a href="gettingstartedfast.html"
title="previous chapter">Getting Started Fast</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="reference.html" <p class="topless"><a href="reference.html"
title="previous chapter">API Reference</a></p> title="next chapter">API Reference</a></p>
<div role="note" aria-label="source link"> <div role="note" aria-label="source link">
<h3>This Page</h3> <h3>This Page</h3>
<ul class="this-page-menu"> <ul class="this-page-menu">
@@ -791,8 +849,11 @@ proof 11
>index</a></li> >index</a></li>
<li class="right" > <li class="right" >
<a href="reference.html" title="API Reference" <a href="reference.html" title="API Reference"
>next</a> |</li>
<li class="right" >
<a href="gettingstartedfast.html" title="Getting Started Fast"
>previous</a> |</li> >previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.0 beta documentation</a> &#187;</li> <li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Understanding Reticulum</a></li> <li class="nav-item nav-item-this"><a href="">Understanding Reticulum</a></li>
</ul> </ul>
</div> </div>
+14 -7
View File
@@ -5,7 +5,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>What is Reticulum? &#8212; Reticulum Network Stack 0.2.0 beta documentation</title> <title>What is Reticulum? &#8212; Reticulum Network Stack 0.2.1 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" /> <link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -31,7 +31,7 @@
<li class="right" > <li class="right" >
<a href="index.html" title="Reticulum Network Stack Manual" <a href="index.html" title="Reticulum Network Stack Manual"
accesskey="P">previous</a> |</li> accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.0 beta documentation</a> &#187;</li> <li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">What is Reticulum?</a></li> <li class="nav-item nav-item-this"><a href="">What is Reticulum?</a></li>
</ul> </ul>
</div> </div>
@@ -59,13 +59,14 @@
<ul class="simple"> <ul class="simple">
<li><p>Coordination-less globally unique adressing and identification</p></li> <li><p>Coordination-less globally unique adressing and identification</p></li>
<li><p>Fully self-configuring multi-hop routing</p></li> <li><p>Fully self-configuring multi-hop routing</p></li>
<li><p>Asymmetric RSA encryption and signatures as basis for all communication</p></li> <li><p>Asymmetric X25519 encryption and Ed25519 signatures as a basis for all communication</p></li>
<li><p>Perfect Forward Secrecy on links with ephemereal Elliptic Curve Diffie-Hellman keys (on Curve25519)</p></li> <li><p>Forward Secrecy with ephemereal Elliptic Curve Diffie-Hellman keys on Curve25519</p></li>
<li><p>Reticulum uses the Fernet specification for encryption on links and to group destinations</p> <li><p>Reticulum uses the <a class="reference external" href="https://github.com/fernet/spec/blob/master/Spec.md">Fernet</a> specification for encryption</p>
<ul> <ul>
<li><p>AES-128 in CBC mode with PKCS7 padding</p></li> <li><p>AES-128 in CBC mode with PKCS7 padding</p></li>
<li><p>HMAC using SHA256 for authentication</p></li> <li><p>HMAC using SHA256 for authentication</p></li>
<li><p>IVs are generated through os.urandom()</p></li> <li><p>IVs are generated through os.urandom()</p></li>
<li><p>Keys are ephemeral and derived from an ECDH key exchange on Curve25519</p></li>
</ul> </ul>
</li> </li>
<li><p>Unforgeable packet delivery confirmations</p></li> <li><p>Unforgeable packet delivery confirmations</p></li>
@@ -78,11 +79,17 @@
<li><p>The API is very easy to use, and provides transfer progress</p></li> <li><p>The API is very easy to use, and provides transfer progress</p></li>
</ul> </ul>
</li> </li>
<li><p>Efficient link establishment</p>
<ul>
<li><p>Total bandwidth cost of setting up a link is only 3 packets, totalling 240 bytes</p></li>
<li><p>Low cost of keeping links open at only 0.62 bits per second</p></li>
</ul>
</li>
</ul> </ul>
</div> </div>
<div class="section" id="where-can-reticulum-be-used"> <div class="section" id="where-can-reticulum-be-used">
<h2>Where can Reticulum be Used?<a class="headerlink" href="#where-can-reticulum-be-used" title="Permalink to this headline"></a></h2> <h2>Where can Reticulum be Used?<a class="headerlink" href="#where-can-reticulum-be-used" title="Permalink to this headline"></a></h2>
<p>On practically any hardware that can support at least a half-duplex channel <p>Over practically any medium that can support at least a half-duplex channel
with 1.000 bits per second throughput, and an MTU of 500 bytes. Data radios, with 1.000 bits per second throughput, and an MTU of 500 bytes. Data radios,
modems, LoRa radios, serial lines, AX.25 TNCs, amateur radio digital modes, modems, LoRa radios, serial lines, AX.25 TNCs, amateur radio digital modes,
ad-hoc WiFi, free-space optical links and similar systems are all examples ad-hoc WiFi, free-space optical links and similar systems are all examples
@@ -174,7 +181,7 @@ network, and vice versa.</p>
<li class="right" > <li class="right" >
<a href="index.html" title="Reticulum Network Stack Manual" <a href="index.html" title="Reticulum Network Stack Manual"
>previous</a> |</li> >previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.0 beta documentation</a> &#187;</li> <li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">What is Reticulum?</a></li> <li class="nav-item nav-item-this"><a href="">What is Reticulum?</a></li>
</ul> </ul>
</div> </div>
+1 -1
View File
@@ -22,7 +22,7 @@ copyright = '2021, Mark Qvist'
author = 'Mark Qvist' author = 'Mark Qvist'
# The full version, including alpha/beta/rc tags # The full version, including alpha/beta/rc tags
release = '0.2.0 beta' release = '0.2.1 beta'
# -- General configuration --------------------------------------------------- # -- General configuration ---------------------------------------------------
+1 -2
View File
@@ -1,7 +1,6 @@
******************** ********************
Getting Started Fast Getting Started Fast
******************** ********************
What do we want to do? Something! When do we want to do it? Right now! Let's go.
The best way to get started with the Reticulum Network Stack depends on what The best way to get started with the Reticulum Network Stack depends on what
you want to do. This guide will outline sensible starting paths for different you want to do. This guide will outline sensible starting paths for different
@@ -23,7 +22,7 @@ in the development for the messaging and information-sharing protocol
Develop a Program with Reticulum Develop a Program with Reticulum
=========================================== ===========================================
If you want to develop programs that use Reticulum, the easiest way to get If you want to develop programs that use Reticulum, the easiest way to get
started is to install Reticulum via pip: started is to install the latest release of Reticulum via pip:
.. code:: .. code::
+2 -2
View File
@@ -10,9 +10,9 @@ the development of Reticulum itself.
whatis whatis
gettingstartedfast gettingstartedfast
examples
reference
understanding understanding
reference
examples
Indices and Tables Indices and Tables
+140 -93
View File
@@ -157,12 +157,16 @@ destinations. Reticulum uses three different basic destination types, and one sp
Destination Naming Destination Naming
^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
Destinations are created and named in an easy to understand dotted notation of *aspects* , and Destinations are created and named in an easy to understand dotted notation of *aspects*, and
represented on the network as a hash of this value. The hash is a SHA-256 truncated to 80 bits. The represented on the network as a hash of this value. The hash is a SHA-256 truncated to 80 bits. The
top level aspect should always be a unique identifier for the application using the destination. top level aspect should always be a unique identifier for the application using the destination.
The next levels of aspects can be defined in any way by the creator of the application. For example, The next levels of aspects can be defined in any way by the creator of the application.
a destination for a environmental monitoring application could be made up of the application name, a
device type and measurement type, like this: Aspects can be as long and as plentiful as required, and a resulting long destination name will not
impact efficiency, as names are always represented as truncated SHA-256 hashes on the network.
As an example, a destination for a environmental monitoring application could be made up of the
application name, a device type and measurement type, like this:
.. code-block:: text .. code-block:: text
@@ -201,9 +205,8 @@ To recap, the different destination types should be used in the following situat
* **Single** * **Single**
When private communication between two endpoints is needed. Supports multiple hops. When private communication between two endpoints is needed. Supports multiple hops.
* **Group** * **Group**
When private communication between two or more endpoints is needed. More efficient in When private communication between two or more endpoints is needed. Supports multiple hops
data usage than *single* destinations. Supports multiple hops indirectly, but must first be indirectly, but must first be established through a *single* destination.
established through a *single* destination.
* **Plain** * **Plain**
When plain-text communication is desirable, for example when broadcasting information. When plain-text communication is desirable, for example when broadcasting information.
@@ -214,9 +217,9 @@ an unknown public key from the network, as all participating nodes serve as a di
of public keys. of public keys.
Note that public key information can be shared and verified in many other ways than using the Note that public key information can be shared and verified in many other ways than using the
built-in methodology, and that it is therefore not required to use the announce/request functionality. built-in *announce* functionality, and that it is therefore not required to use the announce/request
It is by far the easiest though, and should definitely be used if there is not a good reason for functionality to obtain public keys. It is by far the easiest though, and should definitely be used
doing it differently. if there is not a good reason for doing it differently.
.. _understanding-keyannouncements: .. _understanding-keyannouncements:
@@ -235,7 +238,7 @@ contain the following information:
* The announcers public key * The announcers public key
* Application specific data, in this case the users nickname and availability status * Application specific data, in this case the users nickname and availability status
* A random blob, making each new announce unique * A random blob, making each new announce unique
* A signature of the above information, verifying authenticity * An Ed25519 signature of the above information, verifying authenticity
With this information, any Reticulum node that receives it will be able to reconstruct an outgoing With this information, any Reticulum node that receives it will be able to reconstruct an outgoing
destination to securely communicate with that destination. You might have noticed that there is one destination to securely communicate with that destination. You might have noticed that there is one
@@ -244,8 +247,9 @@ the aspect names of the destination. These are intentionally left out to save ba
will be implicit in almost all cases. If a destination name is not entirely implicit, information can be will be implicit in almost all cases. If a destination name is not entirely implicit, information can be
included in the application specific data part that will allow the receiver to infer the naming. included in the application specific data part that will allow the receiver to infer the naming.
It is important to note that announcements will be forwarded throughout the network according to a It is important to note that announces will be forwarded throughout the network according to a
certain pattern. This will be detailed later. certain pattern. This will be detailed in the section
:ref:`The Announce Mechanism in Detail<understanding-announce>`.
Seeing how *single* destinations are always tied to a private/public key pair leads us to the next topic. Seeing how *single* destinations are always tied to a private/public key pair leads us to the next topic.
@@ -268,8 +272,8 @@ the identity first, and then link it to created destinations.
Building upon the simple messenger example, we could use an identity to represent the user of the Building upon the simple messenger example, we could use an identity to represent the user of the
application. Destinations created will then be linked to this identity to allow communication to application. Destinations created will then be linked to this identity to allow communication to
reach the user. In such a case it is of great importance to store the users identity securely and reach the user. In all cases it is of great importance to store the private keys associated with any
privately. Reticulum Identity securely and privately.
.. _understanding-gettingfurther: .. _understanding-gettingfurther:
@@ -279,8 +283,9 @@ Getting Further
The above functions and principles form the core of Reticulum, and would suffice to create The above functions and principles form the core of Reticulum, and would suffice to create
functional networked applications in local clusters, for example over radio links where all interested functional networked applications in local clusters, for example over radio links where all interested
nodes can directly hear each other. But to be truly useful, we need a way to direct traffic over multiple nodes can directly hear each other. But to be truly useful, we need a way to direct traffic over multiple
hops in the network. In the next sections, two concepts that allow this will be introduced, *paths* and hops in the network.
*links*.
In the following sections, two concepts that allow this will be introduced, *paths* and *links*.
.. _understanding-transport: .. _understanding-transport:
@@ -298,70 +303,28 @@ useable over bandwidth-limited, high-latency links.
To overcome such challenges, Reticulums *Transport* system uses public-key cryptography to To overcome such challenges, Reticulums *Transport* system uses public-key cryptography to
implement the concept of *paths* that allow discovery of how to get information to a certain implement the concept of *paths* that allow discovery of how to get information to a certain
destination, and *resources* that help make reliable data transfer more efficient. destination. It is important to note that no single node in a Reticulum network knows the complete
path to a destination. Every Transport node participating in a Reticulum network will only
know what the most direct way to get a packet one hop closer to it's destination is.
.. _understanding-paths: .. _understanding-announce:
Reaching the Destination The Announce Mechanism in Detail
------------------------ --------------------------------
In networks with changing topology and trustless connectivity, nodes need a way to establish When an *announce* is transmitted by a node, it will be forwarded by any node receiving it, but
*verified connectivity* with each other. Since the network is assumed to be trustless, Reticulum according to some specific rules:
must provide a way to guarantee that the peer you are communicating with is actually who you
expect. To do this, the following process is employed:
* | First, the node that wishes to establish connectivity will send out a special packet, that * | If this exact announce has already been received before, ignore it.
traverses the network and locates the desired destination. Along the way, the nodes that
forward the packet will take note of this *link request*.
* | Second, if the destination accepts the *link request* , it will send back a packet that proves the * | If not, record into a table which node the announce was received from, and how many times in
authenticity of its identity (and the receipt of the link request) to the initiating node. All
nodes that initially forwarded the packet will also be able to verify this proof, and thus
accept the validity of the *link* throughout the network.
* | When the validity of the *link* has been accepted by forwarding nodes, these nodes will
remember the *link* , and it can subsequently be used by referring to a hash representing it.
* | As a part of the *link request* , a Diffie-Hellman key exchange takes place, that sets up an
efficient symmetrically encrypted tunnel between the two nodes, using elliptic curve
cryptography. As such, this mode of communication is preferred, even for situations when
nodes can directly communicate, when the amount of data to be exchanged numbers in the
tens of packets.
* | When a *link* has been set up, it automatically provides message receipt functionality, so the
sending node can obtain verified confirmation that the information reached the intended
recipient.
In a moment, we will discuss the specifics of how this methodology is implemented, but lets first
recap what purposes this serves. We first ensure that the node answering our request is actually the
one we want to communicate with, and not a malicious actor pretending to be so. At the same time
we establish an efficient encrypted channel. The setup of this is relatively cheap in terms of
bandwidth, so it can be used just for a short exchange, and then recreated as needed, which will also
rotate encryption keys, but the link can also be kept alive for longer periods of time, if this is
more suitable to the application. The amount of bandwidth used on keeping a link open is practically
negligible. The procedure also inserts the *link id* , a hash calculated from the link request packet,
into the memory of forwarding nodes, which means that the communicating nodes can thereafter reach each
other simply by referring to this *link id*.
Step 1: Pathfinding
^^^^^^^^^^^^^^^^^^^
The pathfinding method builds on the *announce* functionality discussed earlier. When an announce
is sent out by a node, it will be forwarded by any node receiving it, but according to some specific
rules:
* | If this announce has already been received before, ignore it.
* | Record into a table which node the announce was received from, and how many times in
total it has been retransmitted to get here. total it has been retransmitted to get here.
* | If the announce has been retransmitted *m+1* times, it will not be forwarded. By default, *m* is * | If the announce has been retransmitted *m+1* times, it will not be forwarded. By default, *m* is
set to 18. set to 18.
* | The announce will be assigned a delay *d* = c\ :sup:`h` seconds, where *c* is a decay constant, by * | The announce will be assigned a delay *d* = c\ :sup:`h` seconds, where *c* is a decay constant, and *h* is the amount of times this packet has already been forwarded.
default 2, and *h* is the amount of times this packet has already been forwarded.
* | The packet will be given a priority *p = 1/d*. * | The packet will be given a priority *p = 1/d*.
@@ -370,10 +333,11 @@ rules:
not utilized by other traffic, the announce will be forwarded. not utilized by other traffic, the announce will be forwarded.
* | If no other nodes are heard retransmitting the announce with a greater hop count than when * | If no other nodes are heard retransmitting the announce with a greater hop count than when
it left this node, transmitting it will be retried *r* times. By default, *r* is set to 2. Retries follow it left this node, transmitting it will be retried *r* times. By default, *r* is set to 1. Retries
same rules as above, with the exception that it must wait for at least *d* = c\ :sup:`h+1` + t seconds, ie., follow same rules as above, with the exception that it must wait for at least *d* = c\ :sup:`h+1` +
the amount of time it would take the next node to retransmit the packet. By default, *t* is set to t + rand(0, rw) seconds. This amount of time is equal to the amount of time it would take the next
10. node to retransmit the packet, plus a random window. By default, *t* is set to 10 seconds, and the
random window *rw* is set to 10 seconds.
* | If a newer announce from the same destination arrives, while an identical one is already in * | If a newer announce from the same destination arrives, while an identical one is already in
the queue, the newest announce is discarded. If the newest announce contains different the queue, the newest announce is discarded. If the newest announce contains different
@@ -392,14 +356,95 @@ distance of *Lavg =* 15 kilometers, an announce will be able to propagate outwar
kilometers in 34 minutes, and a *maximum announce radius* of 270 kilometers in approximately 3 kilometers in 34 minutes, and a *maximum announce radius* of 270 kilometers in approximately 3
days. days.
Step 2: Link Establishment .. _understanding-paths:
^^^^^^^^^^^^^^^^^^^^^^^^^^
After seeing how the conditions for finding a path through the network are created, we will now Reaching the Destination
explore how two nodes can establish reliable communications over multiple hops. The *link* in ------------------------
Reticulum terminology should not be viewed as a direct node-to-node link on the physical layer, but
as an abstract channel, that can be open for any amount of time, and can span an arbitrary number In networks with changing topology and trustless connectivity, nodes need a way to establish
of hops, where information will be exchanged between two nodes. *verified connectivity* with each other. Since the network is assumed to be trustless, Reticulum
must provide a way to guarantee that the peer you are communicating with is actually who you
expect. Reticulum offers two ways to do this.
For exchanges of small amounts of information, Reticulum offers the *Packet* API, which works exactly like you would expect - on a per packet level. The following process is employed when sending a packet:
* | A packet is always created with an associated destination and some payload data. When the packet is sent
to a *single* destination type, Reticulum will automatically create an ephemeral encryption key, perform
an ECDH key exchange with the destinations public key, and encrypt the information.
* | It is important to note that this key exchange does not require any network traffic. The sender already
knows the public key of the destination from an earlier received *announce*, and can thus perform the ECDH
key exchange locally, before sending the packet.
* | The public part of the newly generated ephemeral key-pair is included with the encrypted token, and sent
along with the encrypted payload data in the packet.
* | When the destination receives the packet, it can itself perform an ECDH key exchange and decrypt the
packet.
* | A new ephemeral key is used for every packet sent in this way, and forward secrecy is guaranteed on a
per packet level.
* | Once the packet has been received and decrypted by the addressed destination, that destination can opt
to *prove* its receipt of the packet. It does this by calculating the SHA-256 hash of the received packet,
and signing this hash with it's Ed25519 signing key. Transport nodes in the network can then direct this
*proof* back to the packets origin, where the signature can be verified against the destinations known
public signing key.
* | In case the packet is addressed to a *group* destination type, the packet will be encrypted with the
pre-shared AES-128 key associated with the destination. In case the packet is addressed to a *plain*
destination type, the payload data will not be encrypted. Neither of these two destination types offer
forward secrecy. In general, it is recommended to always use the *single* destination type, unless it is
strictly necessary to use one of the others.
For exchanges of larger amounts of data, or when longer sessions of bidirectional communication is desired, Reticulum offers the *Link* API. To establish a *link*, the following process is employed:
* | First, the node that wishes to establish a link will send out a special packet, that
traverses the network and locates the desired destination. Along the way, the nodes that
forward the packet will take note of this *link request*.
* | Second, if the destination accepts the *link request* , it will send back a packet that proves the
authenticity of its identity (and the receipt of the link request) to the initiating node. All
nodes that initially forwarded the packet will also be able to verify this proof, and thus
accept the validity of the *link* throughout the network.
* | When the validity of the *link* has been accepted by forwarding nodes, these nodes will
remember the *link* , and it can subsequently be used by referring to a hash representing it.
* | As a part of the *link request* , a Diffie-Hellman key exchange takes place, that sets up an
efficiently encrypted tunnel between the two nodes, using elliptic curve cryptography. As such,
this mode of communication is preferred, even for situations when nodes can directly communicate,
when the amount of data to be exchanged numbers in the tens of packets.
* | When a *link* has been set up, it automatically provides message receipt functionality, through
the same *proof* mechanism discussed before, so the sending node can obtain verified confirmation
that the information reached the intended recipient.
In a moment, we will discuss the details of how this methodology is implemented, but lets first
recap what purposes this methodology serves. We first ensure that the node answering our request
is actually the one we want to communicate with, and not a malicious actor pretending to be so.
At the same time we establish an efficient encrypted channel. The setup of this is relatively cheap in
terms of bandwidth, so it can be used just for a short exchange, and then recreated as needed, which will
also rotate encryption keys. The link can also be kept alive for longer periods of time, if this is
more suitable to the application. The procedure also inserts the *link id* , a hash calculated from the link request packet, into the memory of forwarding nodes, which means that the communicating nodes can thereafter reach each other simply by referring to this *link id*.
The combined bandwidth cost of setting up a link is 3 packets totalling 240 bytes (more info in the
:ref:`Binary Packet Format<understanding-packetformat>` section). The amount of bandwidth used on keeping
a link open is practically negligible, at 0.62 bits per second. Even on a slow 1200 bits per second packet
radio channel, 100 concurrent links will still leave 95% channel capacity for actual data.
Link Establishment in Detail
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
After exploring the basics of the announce mechanism, finding a path through the network, and an overview
of the link establishment procedure, this section will go into greater detail about the Reticulum link
establishment process.
The *link* in Reticulum terminology should not be viewed as a direct node-to-node link on the
physical layer, but as an abstract channel, that can be open for any amount of time, and can span
an arbitrary number of hops, where information will be exchanged between two nodes.
* | When a node in the network wants to establish verified connectivity with another node, it * | When a node in the network wants to establish verified connectivity with another node, it
@@ -412,25 +457,25 @@ of hops, where information will be exchanged between two nodes.
considered as single public key for simplicity in this explanation.* considered as single public key for simplicity in this explanation.*
* | The *link request* is addressed to the destination hash of the desired destination, and * | The *link request* is addressed to the destination hash of the desired destination, and
contains the following data: The newly generated X25519 public key *LKi*. The contents contains the following data: The newly generated X25519 public key *LKi*.
are encrypted with the RSA public key of the destination and tramsitted over the network.
* | The broadcasted packet will be directed through the network according to the rules laid out * | The broadcasted packet will be directed through the network according to the rules laid out
previously. previously.
* | Any node that forwards the link request will store a *link id* in its *link table* , along with the * | Any node that forwards the link request will store a *link id* in its *link table* , along with the
amount of hops the packet had taken when received. The link id is a hash of the entire link amount of hops the packet had taken when received. The link id is a hash of the entire link
request packet. If the path is not *proven* within some set amount of time, the entry will be request packet. If the link request packet is not *proven* by the addressed destination within some
dropped from the *link table* again. set amount of time, the entry will be dropped from the *link table* again.
* | When the destination receives the link request packet, it will decrypt it and decide whether to * | When the destination receives the link request packet, it will decide whether to accept the request.
accept the request. If it is accepted, the destination will also generate a new X25519 private/public If it is accepted, the destination will also generate a new X25519 private/public key pair, and
key pair, and perform a Diffie Hellman Key Exchange, deriving a new symmetric key that will be used perform a Diffie Hellman Key Exchange, deriving a new symmetric key that will be used to encrypt the
to encrypt the channel, once it has been established. channel, once it has been established.
* | A *link proof* packet is now constructed and transmitted over the network. This packet is * | A *link proof* packet is now constructed and transmitted over the network. This packet is
addressed to the *link id* of the *link*. It contains the following data: The newly generated X25519 addressed to the *link id* of the *link*. It contains the following data: The newly generated X25519
public key *LKr* and an RSA-1024 signature of the *link id* and *LKr*. public key *LKr* and an Ed25519 signature of the *link id* and *LKr* made by the signing key of
the addressed destination.
* | By verifying this *link proof* packet, all nodes that originally transported the *link request* * | By verifying this *link proof* packet, all nodes that originally transported the *link request*
packet to the destination from the originator can now verify that the intended destination received packet to the destination from the originator can now verify that the intended destination received
@@ -556,6 +601,8 @@ the light of Reticulums goal of equal access, doing so would need to be the subj
investigation of the consequences first. investigation of the consequences first.
.. _understanding-packetformat:
Binary Packet Format Binary Packet Format
-------------------- --------------------
@@ -651,8 +698,8 @@ Binary Packet Format
wire size including all fields. wire size including all fields.
- Path Request : 33 bytes - Path Request : 33 bytes
- Announce : 323 bytes - Announce : 151 bytes
- Link Request : 141 bytes - Link Request : 77 bytes
- Link Proof : 205 bytes - Link Proof : 77 bytes
- Link RTT packet : 86 bytes - Link RTT packet : 86 bytes
- Link keepalive : 14 bytes - Link keepalive : 14 bytes
+12 -4
View File
@@ -25,11 +25,11 @@ What does Reticulum Offer?
* Fully self-configuring multi-hop routing * Fully self-configuring multi-hop routing
* Asymmetric RSA encryption and signatures as basis for all communication * Asymmetric X25519 encryption and Ed25519 signatures as a basis for all communication
* Perfect Forward Secrecy on links with ephemereal Elliptic Curve Diffie-Hellman keys (on Curve25519) * Forward Secrecy with ephemereal Elliptic Curve Diffie-Hellman keys on Curve25519
* Reticulum uses the Fernet specification for encryption on links and to group destinations * Reticulum uses the `Fernet <https://github.com/fernet/spec/blob/master/Spec.md>`_ specification for encryption
* AES-128 in CBC mode with PKCS7 padding * AES-128 in CBC mode with PKCS7 padding
@@ -37,6 +37,8 @@ What does Reticulum Offer?
* IVs are generated through os.urandom() * IVs are generated through os.urandom()
* Keys are ephemeral and derived from an ECDH key exchange on Curve25519
* Unforgeable packet delivery confirmations * Unforgeable packet delivery confirmations
* A variety of supported interface types * A variety of supported interface types
@@ -51,10 +53,16 @@ What does Reticulum Offer?
* The API is very easy to use, and provides transfer progress * The API is very easy to use, and provides transfer progress
* Efficient link establishment
* Total bandwidth cost of setting up a link is only 3 packets, totalling 240 bytes
* Low cost of keeping links open at only 0.62 bits per second
Where can Reticulum be Used? Where can Reticulum be Used?
============================ ============================
On practically any hardware that can support at least a half-duplex channel Over practically any medium that can support at least a half-duplex channel
with 1.000 bits per second throughput, and an MTU of 500 bytes. Data radios, with 1.000 bits per second throughput, and an MTU of 500 bytes. Data radios,
modems, LoRa radios, serial lines, AX.25 TNCs, amateur radio digital modes, modems, LoRa radios, serial lines, AX.25 TNCs, amateur radio digital modes,
ad-hoc WiFi, free-space optical links and similar systems are all examples ad-hoc WiFi, free-space optical links and similar systems are all examples
+1 -1
View File
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
setuptools.setup( setuptools.setup(
name="rns", name="rns",
version="0.2.0", version="0.2.1",
author="Mark Qvist", author="Mark Qvist",
author_email="mark@unsigned.io", author_email="mark@unsigned.io",
description="Self-configuring, encrypted and resilient mesh networking stack for LoRa, packet radio, WiFi and everything in between", description="Self-configuring, encrypted and resilient mesh networking stack for LoRa, packet radio, WiFi and everything in between",