lib/reticulum/src/carrier/root.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 //! The unit of bytes a node hands to one network interface, and an interface
2 //! that keeps those bytes in memory.
3 //!
4 //! A Reticulum node sends over whatever moves bytes, a radio, a serial line, or
5 //! a socket, so the code above the interface deals in one unit and one index,
6 //! whatever the device. That unit has to have a size the program knows before
7 //! it starts, because a node holds those units in storage the caller supplied.
8 //! Testing a protocol needs an interface that gives the same answer on every
9 //! run.
10 //!
11 //! One unit runs longer than the 500-byte packet inside it, because a closed
12 //! network appends an authentication code of up to 64 bytes. A real device
13 //! brings a clock and a driver with it, and both make a test answer differently
14 //! from one run to the next.
15 //!
16 //! The subtree follows Reticulum 1.5.0, the reference implementation, pinned to
17 //! one upstream commit by the package README and the generated conformance
18 //! corpus. What it takes is the frame bound of Reticulum@1.5.0
19 //! RNS/Transport.py:1247 and Reticulum@1.5.0 RNS/Reticulum.py:800.
20 //!
21 //! Each unit (a *frame*) is one fixed 564-byte value with a length beside it,
22 //! holding one packet plus at most a 64-byte signature, so a queue of frames is
23 //! a plain array in caller storage. The in-memory interface is a bounded queue
24 //! carved out of caller storage, which hands frames back in the order it took
25 //! them and refuses a frame once it is full, leaving what it holds untouched.
26 //! The subtree names its pieces: the frame bound, the carrier index, the frame,
27 //! and the in-memory interface.
28 //!
29 //! - *carrier*: one network interface a node sends and receives frames over,
30 //! named by a byte index.
31
32 const wire = @import("../wire/root.zig");
33
34 /// 564 bytes, the most one frame holds, a 500-byte packet plus at most a
35 /// 64-byte Ed25519 signature. A frame is the bytes handed to one network
36 /// interface. A caller sizes the buffer it reads an arriving frame into, and
37 /// the storage it hands the in-memory interface, by this bound, following
38 /// Reticulum@1.5.0 RNS/Transport.py:1247 and Reticulum@1.5.0
39 /// RNS/Reticulum.py:800.
40 pub const frame_bytes_max: usize = @as(usize, wire.mtu) + 64;
41
42 pub const Index = u8;
43
44 pub const Frame = struct {
45 bytes: [frame_bytes_max]u8 = @splat(0),
46 len: u16 = 0,
47
48 pub const InitError = error{TooLong};
49
50 pub fn init(bytes: []const u8) InitError!Frame {
51 if (bytes.len > frame_bytes_max) return error.TooLong;
52 var frame = Frame{};
53 @memcpy(frame.bytes[0..bytes.len], bytes);
54 frame.len = @intCast(bytes.len);
55 return frame;
56 }
57
58 pub fn slice(self: *const Frame) []const u8 {
59 std.debug.assert(self.len <= frame_bytes_max);
60 return self.bytes[0..self.len];
61 }
62 };
63
64 const std = @import("std");
65
66 pub const Memory = @import("memory.zig").Memory;