mirror of
https://github.com/ion232/reticulum-zig.git
synced 2025-12-22 06:37:05 +00:00
examples: add tcp test net example
This commit is contained in:
@@ -41,7 +41,7 @@ pub fn init(ally: Allocator, system: *System, identity: ?Identity, options: Opti
|
||||
var main_endpoint = try endpoint_builder
|
||||
.setIdentity(identity orelse try Identity.random(&system.rng))
|
||||
.setDirection(.in)
|
||||
.setMethod(.single)
|
||||
.setVariant(.single)
|
||||
.setName(try Name.init(options.name, &.{}, ally))
|
||||
.build();
|
||||
defer main_endpoint.deinit();
|
||||
@@ -180,7 +180,7 @@ fn packetOut(self: *Self, interface: *Interface, packet: *Packet) !bool {
|
||||
_ = self;
|
||||
|
||||
const purpose = packet.header.purpose;
|
||||
const method = packet.header.method;
|
||||
const variant = packet.header.endpoint;
|
||||
const hops = packet.header.hops;
|
||||
|
||||
if (purpose == .announce) {
|
||||
@@ -188,7 +188,7 @@ fn packetOut(self: *Self, interface: *Interface, packet: *Packet) !bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (method == .plain and hops == 0) {
|
||||
if (variant == .plain and hops == 0) {
|
||||
try interface.outgoing.push(.{ .packet = packet.* });
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@ pub const Fernet = @import("crypto/Fernet.zig");
|
||||
pub const Hash = @import("crypto/Hash.zig");
|
||||
pub const Identity = @import("crypto/Identity.zig");
|
||||
pub const Ed25519 = std.crypto.sign.Ed25519;
|
||||
pub const X25519 = @import("crypto/X25519.zig");
|
||||
pub const X25519 = std.crypto.dh.X25519;
|
||||
|
||||
@@ -8,7 +8,7 @@ pub const Direction = enum {
|
||||
out,
|
||||
};
|
||||
|
||||
pub const Method = enum(u2) {
|
||||
pub const Variant = enum(u2) {
|
||||
single,
|
||||
group,
|
||||
plain,
|
||||
|
||||
@@ -6,7 +6,7 @@ const endpoint = @import("../endpoint.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Identity = crypto.Identity;
|
||||
const Direction = endpoint.Direction;
|
||||
const Method = endpoint.Method;
|
||||
const Variant = endpoint.Variant;
|
||||
const Name = endpoint.Name;
|
||||
const Hash = crypto.Hash;
|
||||
const Managed = @import("Managed.zig");
|
||||
@@ -17,14 +17,14 @@ pub const Error = error{
|
||||
HasIdentity,
|
||||
MissingIdentity,
|
||||
MissingDirection,
|
||||
MissingMethod,
|
||||
MissingVariant,
|
||||
MissingName,
|
||||
} || Allocator.Error;
|
||||
|
||||
ally: Allocator,
|
||||
identity: ?Identity,
|
||||
direction: ?Direction,
|
||||
method: ?Method,
|
||||
variant: ?Variant,
|
||||
name: ?Name,
|
||||
|
||||
pub fn init(ally: Allocator) Self {
|
||||
@@ -32,7 +32,7 @@ pub fn init(ally: Allocator) Self {
|
||||
.ally = ally,
|
||||
.identity = null,
|
||||
.direction = null,
|
||||
.method = null,
|
||||
.variant = null,
|
||||
.name = null,
|
||||
};
|
||||
}
|
||||
@@ -47,8 +47,8 @@ pub fn setDirection(self: *Self, direction: Direction) *Self {
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn setMethod(self: *Self, method: Method) *Self {
|
||||
self.method = method;
|
||||
pub fn setVariant(self: *Self, variant: Variant) *Self {
|
||||
self.variant = variant;
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -59,12 +59,12 @@ pub fn setName(self: *Self, name: Name) *Self {
|
||||
|
||||
pub fn build(self: *Self) Error!Managed {
|
||||
const direction = self.direction orelse return Error.MissingDirection;
|
||||
const method = self.method orelse return Error.MissingMethod;
|
||||
const variant = self.variant orelse return Error.MissingVariant;
|
||||
const name = self.name orelse return Error.MissingName;
|
||||
|
||||
if (method == .plain and self.identity != null) {
|
||||
if (variant == .plain and self.identity != null) {
|
||||
return Error.HasIdentity;
|
||||
} else if (method != .plain and self.identity == null) {
|
||||
} else if (variant != .plain and self.identity == null) {
|
||||
return Error.MissingIdentity;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ pub fn build(self: *Self) Error!Managed {
|
||||
.ally = self.ally,
|
||||
.identity = self.identity,
|
||||
.direction = direction,
|
||||
.method = method,
|
||||
.variant = variant,
|
||||
.name = name,
|
||||
.hash = hash,
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@ const endpoint = @import("../endpoint.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Identity = crypto.Identity;
|
||||
const Direction = endpoint.Direction;
|
||||
const Method = endpoint.Method;
|
||||
const Variant = endpoint.Variant;
|
||||
const Name = endpoint.Name;
|
||||
const Hash = crypto.Hash;
|
||||
|
||||
@@ -15,7 +15,7 @@ const Self = @This();
|
||||
ally: Allocator,
|
||||
identity: ?Identity,
|
||||
direction: Direction,
|
||||
method: Method,
|
||||
variant: Variant,
|
||||
name: Name,
|
||||
hash: Hash,
|
||||
|
||||
@@ -24,7 +24,7 @@ pub fn clone(self: *const Self) !Self {
|
||||
.ally = self.ally,
|
||||
.identity = self.identity,
|
||||
.direction = self.direction,
|
||||
.method = self.method,
|
||||
.variant = self.variant,
|
||||
.name = try self.name.clone(),
|
||||
.hash = self.hash,
|
||||
};
|
||||
|
||||
@@ -88,7 +88,7 @@ test "main" {
|
||||
.setIdentity(try Identity.random(&rng))
|
||||
.setName(try Name.init("endpoint", &.{"main"}, ally))
|
||||
.setDirection(.in)
|
||||
.setMethod(.single)
|
||||
.setVariant(.single)
|
||||
.build();
|
||||
|
||||
break :blk endpoint;
|
||||
|
||||
@@ -110,7 +110,7 @@ pub const Out = union(enum) {
|
||||
@tagName(h.format),
|
||||
@tagName(h.context),
|
||||
@tagName(h.propagation),
|
||||
@tagName(h.method),
|
||||
@tagName(h.endpoint),
|
||||
@tagName(h.purpose),
|
||||
h.hops,
|
||||
});
|
||||
@@ -146,6 +146,9 @@ pub const Out = union(enum) {
|
||||
var timestamp_bytes: [5]u8 = undefined;
|
||||
std.mem.writeInt(u40, ×tamp_bytes, a.timestamp, .big);
|
||||
try f.entry("timestamp", "{x}", .{hex(×tamp_bytes)});
|
||||
if (a.ratchet) |*ratchet| {
|
||||
try f.entry("ratchet", "{x}", .{hex(ratchet)});
|
||||
}
|
||||
try f.entry("signature", "{x}", .{hex(&a.signature.toBytes())});
|
||||
|
||||
if (a.application_data.items.len > 0) {
|
||||
|
||||
102
core/packet.zig
102
core/packet.zig
@@ -1,10 +1,10 @@
|
||||
const std = @import("std");
|
||||
const crypto = @import("crypto.zig");
|
||||
const data = @import("data.zig");
|
||||
const endpoint = @import("endpoint.zig");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Endpoint = @import("endpoint.zig").Managed;
|
||||
const EndpointMethod = @import("endpoint.zig").Method;
|
||||
const Endpoint = endpoint.Managed;
|
||||
const Hash = crypto.Hash;
|
||||
const Identity = crypto.Identity;
|
||||
|
||||
@@ -35,7 +35,7 @@ pub const Payload = union(enum) {
|
||||
name_hash: Hash.Name,
|
||||
noise: Noise,
|
||||
timestamp: Timestamp,
|
||||
// rachet: ?*const [N]u8,
|
||||
ratchet: ?crypto.Identity.Ratchet,
|
||||
signature: crypto.Ed25519.Signature,
|
||||
application_data: data.Bytes,
|
||||
};
|
||||
@@ -58,6 +58,7 @@ pub const Payload = union(enum) {
|
||||
.name_hash = a.name_hash,
|
||||
.noise = a.noise,
|
||||
.timestamp = a.timestamp,
|
||||
.ratchet = a.ratchet,
|
||||
.signature = a.signature,
|
||||
.application_data = try a.application_data.clone(),
|
||||
},
|
||||
@@ -78,6 +79,7 @@ pub const Payload = union(enum) {
|
||||
total += crypto.Hash.name_length;
|
||||
total += @sizeOf(Announce.Noise);
|
||||
total += @sizeOf(Announce.Timestamp);
|
||||
total += if (a.ratchet != null) @sizeOf(crypto.Identity.Ratchet) else 0;
|
||||
total += crypto.Ed25519.Signature.encoded_length;
|
||||
total += a.application_data.items.len;
|
||||
break :blk total;
|
||||
@@ -148,7 +150,7 @@ pub const Header = packed struct(u16) {
|
||||
transport,
|
||||
};
|
||||
|
||||
pub const Method = EndpointMethod;
|
||||
pub const Endpoint = endpoint.Variant;
|
||||
|
||||
pub const Purpose = enum(u2) {
|
||||
data,
|
||||
@@ -158,12 +160,12 @@ pub const Header = packed struct(u16) {
|
||||
};
|
||||
};
|
||||
|
||||
interface: Flag.Interface = .open,
|
||||
format: Flag.Format = .normal,
|
||||
context: Flag.Context = .none,
|
||||
propagation: Flag.Propagation = .broadcast,
|
||||
method: Flag.Method = .single,
|
||||
purpose: Flag.Purpose = .data,
|
||||
endpoint: Flag.Endpoint = .single,
|
||||
propagation: Flag.Propagation = .broadcast,
|
||||
context: Flag.Context = .none,
|
||||
format: Flag.Format = .normal,
|
||||
interface: Flag.Interface = .open,
|
||||
hops: u8 = 0,
|
||||
};
|
||||
|
||||
@@ -190,3 +192,85 @@ pub const Context = enum(u8) {
|
||||
link_request_rtt,
|
||||
link_request_proof,
|
||||
};
|
||||
|
||||
test "validate-raw-announce-roundtrip" {
|
||||
const t = std.testing;
|
||||
const ally = t.allocator;
|
||||
const rng = std.crypto.random;
|
||||
|
||||
// Captured from reference implementation - with framing removed.
|
||||
const raw_announce = "71008133c7ce6d6be9b4070a3b98ee9ecab583dfe79d30200ee5e9f5c5615d45a5b000fb266456840e5f4d010a6fbb4025969f8db5415597e3d7a48431d0534e441d0bdeb78f1064f50b447291dd51617040dc9c40cb5b9adab1314ad270b1297d6fd46ec60bc318e2c0f0d908fc1c2bcdef00686f9b4ef17ec1b73f60b14df6709cb74164bd1890e26ff8a4634bbd855051ef959f413d7f7c8f9ff0f54ee81fb994c4e1975fe6f4b56fb26d2e107bd824d864a6932a2e2c02b1352ad9a31ce1cbeae72902effef1ccdeb7d004fbe527cd39111dc59d0e92c406696f6e323332c0";
|
||||
|
||||
var bytes = std.ArrayList(u8).init(ally);
|
||||
defer bytes.deinit();
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < raw_announce.len) : (i += 2) {
|
||||
const byte = std.fmt.parseInt(u8, raw_announce[i .. i + 2], 16) catch break;
|
||||
try bytes.append(byte);
|
||||
}
|
||||
|
||||
var factory = Factory.init(ally, rng, .{});
|
||||
var p = factory.fromBytes(bytes.items) catch |err| {
|
||||
std.debug.print("Failed to parse packet: {}\n", .{err});
|
||||
return;
|
||||
};
|
||||
defer p.deinit();
|
||||
|
||||
try t.expect(p.header.purpose == .announce);
|
||||
try t.expect(p.header.context == .some);
|
||||
try t.expect(p.payload.announce.ratchet != null);
|
||||
|
||||
try p.validate();
|
||||
|
||||
var buffer: [1024]u8 = undefined;
|
||||
|
||||
var q = factory.fromBytes(try p.write(&buffer)) catch |err| {
|
||||
std.debug.print("Failed to parse packet: {}\n", .{err});
|
||||
return;
|
||||
};
|
||||
defer q.deinit();
|
||||
|
||||
try t.expect(q.header.purpose == .announce);
|
||||
try t.expect(q.header.context == .some);
|
||||
try t.expect(q.payload.announce.ratchet != null);
|
||||
|
||||
try q.validate();
|
||||
}
|
||||
|
||||
test "validate-make-announce" {
|
||||
const t = std.testing;
|
||||
const ally = t.allocator;
|
||||
var rng = std.crypto.random;
|
||||
|
||||
var builder = endpoint.Builder.init(ally);
|
||||
defer builder.deinit();
|
||||
|
||||
var announce_endpoint = try builder
|
||||
.setIdentity(try crypto.Identity.random(&rng))
|
||||
.setDirection(.in)
|
||||
.setVariant(.single)
|
||||
.setName(try endpoint.Name.init("endpoint", &.{"test"}, ally))
|
||||
.build();
|
||||
defer announce_endpoint.deinit();
|
||||
|
||||
const app_data = "some application data";
|
||||
const now = 123456789;
|
||||
var factory = Factory.init(ally, rng, .{});
|
||||
var announce_packet = try factory.makeAnnounce(&announce_endpoint, app_data, now);
|
||||
defer announce_packet.deinit();
|
||||
|
||||
var raw_bytes = try data.Bytes.initCapacity(ally, announce_packet.size());
|
||||
raw_bytes.expandToCapacity();
|
||||
defer raw_bytes.deinit();
|
||||
const raw_packet = try announce_packet.write(raw_bytes.items);
|
||||
|
||||
var p = try factory.fromBytes(raw_packet);
|
||||
defer p.deinit();
|
||||
|
||||
try t.expect(p.header.purpose == .announce);
|
||||
try p.validate();
|
||||
|
||||
const announce = p.payload.announce;
|
||||
try t.expectEqualStrings(app_data, announce.application_data.items);
|
||||
}
|
||||
|
||||
@@ -72,8 +72,8 @@ pub fn setTransport(self: *Self, endpoint_hash: Hash.Short, transport_id: Hash.S
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn setMethod(self: *Self, method: Header.Flag.Method) *Self {
|
||||
self.header.method = method;
|
||||
pub fn setVariant(self: *Self, variant: Header.Flag.Endpoint) *Self {
|
||||
self.header.endpoint = variant;
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -89,19 +89,17 @@ pub fn setContext(self: *Self, context: Context) *Self {
|
||||
}
|
||||
|
||||
pub fn setPayload(self: *Self, payload: Payload) *Self {
|
||||
self.header.purpose = switch (payload) {
|
||||
.announce => .announce,
|
||||
else => self.header.purpose,
|
||||
};
|
||||
switch (payload) {
|
||||
.announce => |*a| {
|
||||
self.header.purpose = .announce;
|
||||
self.header.context = if (a.ratchet != null) .some else .none;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
self.payload = payload;
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn appendPayload(self: *Self, payload: []const u8) !*Self {
|
||||
try self.payload.appendSlice(payload);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn build(self: *Self) !Managed {
|
||||
const endpoints = self.endpoints orelse return Error.Incomplete;
|
||||
|
||||
|
||||
@@ -45,10 +45,9 @@ pub fn fromBytes(self: *Self, bytes: []const u8) Error!Packet {
|
||||
index += header_size;
|
||||
|
||||
const both_auth = self.config.access_code != null and header.interface == .authenticated;
|
||||
const both_not_auth = self.config.access_code == null and header.interface == .open;
|
||||
const non_matching_auth = !(both_auth or both_not_auth);
|
||||
const both_open = self.config.access_code == null and header.interface == .open;
|
||||
|
||||
if (non_matching_auth) {
|
||||
if (!(both_auth or both_open)) {
|
||||
return Error.InvalidAuthentication;
|
||||
}
|
||||
|
||||
@@ -81,21 +80,23 @@ pub fn fromBytes(self: *Self, bytes: []const u8) Error!Packet {
|
||||
@memcpy(&endpoint, bytes[index .. index + endpoint.len]);
|
||||
index += endpoint.len;
|
||||
|
||||
const endpoints = packet.Endpoints{ .normal = .{
|
||||
.endpoint = endpoint,
|
||||
} };
|
||||
const endpoints = packet.Endpoints{
|
||||
.normal = .{
|
||||
.endpoint = endpoint,
|
||||
},
|
||||
};
|
||||
|
||||
break :blk endpoints;
|
||||
},
|
||||
.transport => blk: {
|
||||
var endpoint: crypto.Hash.Short = undefined;
|
||||
@memcpy(&endpoint, bytes[index .. index + endpoint.len]);
|
||||
index += endpoint.len;
|
||||
|
||||
var transport_id: crypto.Hash.Short = undefined;
|
||||
@memcpy(&transport_id, bytes[index .. index + transport_id.len]);
|
||||
index += transport_id.len;
|
||||
|
||||
var endpoint: crypto.Hash.Short = undefined;
|
||||
@memcpy(&endpoint, bytes[index .. index + endpoint.len]);
|
||||
index += endpoint.len;
|
||||
|
||||
const endpoints = packet.Endpoints{ .transport = .{
|
||||
.transport_id = transport_id,
|
||||
.endpoint = endpoint,
|
||||
@@ -135,10 +136,20 @@ pub fn fromBytes(self: *Self, bytes: []const u8) Error!Packet {
|
||||
index += signature_key_bytes.len;
|
||||
@memcpy(&announce.name_hash, bytes[index .. index + announce.name_hash.len]);
|
||||
index += announce.name_hash.len;
|
||||
@memcpy(&announce.noise, bytes[index .. index + announce.noise.len]);
|
||||
index += announce.noise.len;
|
||||
announce.timestamp = std.mem.bytesToValue(u40, bytes[index .. index + @sizeOf(Announce.Timestamp)]);
|
||||
index += @sizeOf(Announce.Timestamp);
|
||||
@memcpy(&announce.noise, bytes[index .. index + 5]);
|
||||
index += 5;
|
||||
announce.timestamp = std.mem.readInt(u40, bytes[index .. index + 5][0..5], .big);
|
||||
index += 5;
|
||||
|
||||
if (header.context == .some) {
|
||||
var ratchet: [32]u8 = undefined;
|
||||
@memcpy(&ratchet, bytes[index .. index + 32]);
|
||||
announce.ratchet = ratchet;
|
||||
index += 32;
|
||||
} else {
|
||||
announce.ratchet = null;
|
||||
}
|
||||
|
||||
var signature_bytes: [Signature.encoded_length]u8 = undefined;
|
||||
@memcpy(&signature_bytes, bytes[index .. index + Signature.encoded_length]);
|
||||
announce.signature = Signature.fromBytes(signature_bytes);
|
||||
@@ -153,9 +164,7 @@ pub fn fromBytes(self: *Self, bytes: []const u8) Error!Packet {
|
||||
},
|
||||
else => .{ .raw = blk: {
|
||||
var raw = data.Bytes.init(self.ally);
|
||||
errdefer {
|
||||
raw.deinit();
|
||||
}
|
||||
errdefer raw.deinit();
|
||||
try raw.appendSlice(bytes[index..]);
|
||||
break :blk raw;
|
||||
} },
|
||||
@@ -171,7 +180,6 @@ pub fn fromBytes(self: *Self, bytes: []const u8) Error!Packet {
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: Add ratchet.
|
||||
pub fn makeAnnounce(self: *Self, endpoint: *const Endpoint, application_data: ?[]const u8, now: u64) Error!Packet {
|
||||
const identity = endpoint.identity orelse return Error.MissingIdentity;
|
||||
var announce: packet.Payload.Announce = undefined;
|
||||
@@ -180,6 +188,9 @@ pub fn makeAnnounce(self: *Self, endpoint: *const Endpoint, application_data: ?[
|
||||
announce.name_hash = endpoint.name.hash.name().*;
|
||||
self.rng.bytes(&announce.noise);
|
||||
announce.timestamp = @truncate(now);
|
||||
var ratchet: crypto.Identity.Ratchet = undefined;
|
||||
self.rng.bytes(&ratchet);
|
||||
announce.ratchet = ratchet;
|
||||
announce.application_data = data.Bytes.init(self.ally);
|
||||
|
||||
if (application_data) |app_data| {
|
||||
@@ -196,7 +207,14 @@ pub fn makeAnnounce(self: *Self, endpoint: *const Endpoint, application_data: ?[
|
||||
try bytes.appendSlice(announce.public.signature.bytes[0..]);
|
||||
try bytes.appendSlice(announce.name_hash[0..]);
|
||||
try bytes.appendSlice(announce.noise[0..]);
|
||||
try bytes.appendSlice(&std.mem.toBytes(announce.timestamp));
|
||||
var timestamp_bytes: [5]u8 = undefined;
|
||||
std.mem.writeInt(u40, ×tamp_bytes, announce.timestamp, .big);
|
||||
try bytes.appendSlice(×tamp_bytes);
|
||||
|
||||
if (announce.ratchet) |*r| {
|
||||
try bytes.appendSlice(r[0..]);
|
||||
}
|
||||
|
||||
try bytes.appendSlice(announce.application_data.items);
|
||||
|
||||
break :blk try identity.sign(bytes);
|
||||
@@ -222,51 +240,10 @@ pub fn makePlain(self: *Self, name: Name, payload: packet.Payload) Error!Packet
|
||||
}
|
||||
|
||||
const plain = try builder
|
||||
.setMethod(.plain)
|
||||
.setVariant(.plain)
|
||||
.setEndpoint(name.hash.short().*)
|
||||
.setPayload(payload)
|
||||
.build();
|
||||
|
||||
return plain;
|
||||
}
|
||||
|
||||
test "make-announce-and-validate" {
|
||||
const t = std.testing;
|
||||
const EndpointBuilder = @import("../endpoint.zig").Builder;
|
||||
|
||||
const ally = t.allocator;
|
||||
var rng = std.crypto.random;
|
||||
const config = Interface.Config{};
|
||||
|
||||
var builder = EndpointBuilder.init(ally);
|
||||
defer builder.deinit();
|
||||
|
||||
var endpoint = try builder
|
||||
.setIdentity(try crypto.Identity.random(&rng))
|
||||
.setDirection(.in)
|
||||
.setMethod(.single)
|
||||
.setName(try Name.init("endpoint", &.{"test"}, ally))
|
||||
.build();
|
||||
defer endpoint.deinit();
|
||||
|
||||
const app_data = "some application data";
|
||||
const now = 123456789;
|
||||
var factory1 = Self.init(ally, rng, config);
|
||||
var announce_packet = try factory1.makeAnnounce(&endpoint, app_data, now);
|
||||
defer announce_packet.deinit();
|
||||
|
||||
var packet_bytes = try data.Bytes.initCapacity(ally, announce_packet.size());
|
||||
packet_bytes.expandToCapacity();
|
||||
defer packet_bytes.deinit();
|
||||
const raw_packet = try announce_packet.write(packet_bytes.items);
|
||||
|
||||
var factory2 = Self.init(ally, rng, config);
|
||||
var parsed_packet = try factory2.fromBytes(raw_packet);
|
||||
defer parsed_packet.deinit();
|
||||
|
||||
try t.expect(parsed_packet.header.purpose == .announce);
|
||||
try parsed_packet.validate();
|
||||
|
||||
const announce = parsed_packet.payload.announce;
|
||||
try t.expectEqualStrings(app_data, announce.application_data.items);
|
||||
}
|
||||
|
||||
@@ -43,15 +43,28 @@ pub fn setTransport(self: *Self, transport_id: *const Hash.Short) !void {
|
||||
pub fn validate(self: *const Self) !void {
|
||||
switch (self.payload) {
|
||||
.announce => |a| {
|
||||
var signed_data = std.ArrayList(u8).init(self.ally);
|
||||
defer signed_data.deinit();
|
||||
|
||||
const endpoint_hash = self.endpoints.endpoint();
|
||||
try signed_data.appendSlice(endpoint_hash[0..]);
|
||||
try signed_data.appendSlice(a.public.dh[0..]);
|
||||
try signed_data.appendSlice(a.public.signature.bytes[0..]);
|
||||
try signed_data.appendSlice(a.name_hash[0..]);
|
||||
try signed_data.appendSlice(a.noise[0..]);
|
||||
|
||||
var timestamp_bytes: [5]u8 = undefined;
|
||||
std.mem.writeInt(u40, ×tamp_bytes, a.timestamp, .big);
|
||||
try signed_data.appendSlice(×tamp_bytes);
|
||||
|
||||
if (a.ratchet) |*ratchet| {
|
||||
try signed_data.appendSlice(ratchet[0..]);
|
||||
}
|
||||
|
||||
try signed_data.appendSlice(a.application_data.items);
|
||||
|
||||
var verifier = try a.signature.verifier(a.public.signature);
|
||||
verifier.update(&endpoint_hash);
|
||||
verifier.update(&a.public.dh);
|
||||
verifier.update(&a.public.signature.bytes);
|
||||
verifier.update(&a.name_hash);
|
||||
verifier.update(&a.noise);
|
||||
verifier.update(&std.mem.toBytes(a.timestamp));
|
||||
verifier.update(a.application_data.items);
|
||||
verifier.update(signed_data.items);
|
||||
try verifier.verify();
|
||||
|
||||
const identity = crypto.Identity.fromPublic(a.public);
|
||||
@@ -114,9 +127,16 @@ pub fn write(self: *const Self, buffer: []u8) ![]u8 {
|
||||
i += a.name_hash.len;
|
||||
@memcpy(buffer[i .. i + a.noise.len], &a.noise);
|
||||
i += a.noise.len;
|
||||
const timestamp_bytes = std.mem.asBytes(&a.timestamp);
|
||||
@memcpy(buffer[i .. i + timestamp_bytes.len], timestamp_bytes);
|
||||
var timestamp_bytes: [5]u8 = undefined;
|
||||
std.mem.writeInt(u40, ×tamp_bytes, a.timestamp, .big);
|
||||
@memcpy(buffer[i .. i + timestamp_bytes.len], ×tamp_bytes);
|
||||
i += timestamp_bytes.len;
|
||||
|
||||
if (a.ratchet) |*ratchet| {
|
||||
@memcpy(buffer[i .. i + ratchet.len], ratchet);
|
||||
i += ratchet.len;
|
||||
}
|
||||
|
||||
@memcpy(buffer[i .. i + crypto.Ed25519.Signature.encoded_length], &a.signature.toBytes());
|
||||
i += crypto.Ed25519.Signature.encoded_length;
|
||||
@memcpy(buffer[i .. i + a.application_data.items.len], a.application_data.items);
|
||||
@@ -134,17 +154,17 @@ pub fn write(self: *const Self, buffer: []u8) ![]u8 {
|
||||
|
||||
pub fn hash(self: *const Self) Hash {
|
||||
const header = std.mem.asBytes(&self.header);
|
||||
const method_and_purpose: u8 = std.mem.bytesAsSlice(u4, header)[1];
|
||||
const variant_and_purpose: u8 = std.mem.bytesAsSlice(u4, header)[1];
|
||||
const context = @intFromEnum(self.context);
|
||||
|
||||
var hasher = switch (self.endpoints) {
|
||||
.normal => |normal| Hash.incremental(.{
|
||||
.method_and_purpose = method_and_purpose,
|
||||
.variant_and_purpose = variant_and_purpose,
|
||||
.endpoint = normal.endpoint,
|
||||
.context = context,
|
||||
}),
|
||||
.transport => |transport| Hash.incremental(.{
|
||||
.method_and_purpose = method_and_purpose,
|
||||
.variant_and_purpose = variant_and_purpose,
|
||||
.transport_id = transport.transport_id,
|
||||
.endpoint = transport.endpoint,
|
||||
.context = context,
|
||||
@@ -158,7 +178,12 @@ pub fn hash(self: *const Self) Hash {
|
||||
hasher.update(&announce.public.signature.bytes);
|
||||
hasher.update(&announce.name_hash);
|
||||
hasher.update(&announce.noise);
|
||||
hasher.update(std.mem.asBytes(&announce.timestamp));
|
||||
var timestamp_bytes: [5]u8 = undefined;
|
||||
std.mem.writeInt(u40, ×tamp_bytes, announce.timestamp, .big);
|
||||
hasher.update(×tamp_bytes);
|
||||
if (announce.ratchet) |*ratchet| {
|
||||
hasher.update(ratchet);
|
||||
}
|
||||
hasher.update(&announce.signature.r);
|
||||
hasher.update(&announce.signature.s);
|
||||
hasher.update(announce.application_data.items);
|
||||
|
||||
25
examples/tcp.zig
Normal file
25
examples/tcp.zig
Normal file
@@ -0,0 +1,25 @@
|
||||
const std = @import("std");
|
||||
const core = @import("core");
|
||||
const io = @import("io");
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
defer _ = gpa.deinit();
|
||||
|
||||
const ally = gpa.allocator();
|
||||
var clock = try io.os.Clock.init();
|
||||
var rng = io.os.Rng.init();
|
||||
var system = core.System{
|
||||
.clock = clock.clock(),
|
||||
.rng = rng.rng(),
|
||||
};
|
||||
|
||||
var node = try core.Node.init(ally, &system, null, .{});
|
||||
const host = "amsterdam.connect.reticulum.network";
|
||||
const port = 4965;
|
||||
|
||||
var driver = try io.driver.Tcp.init(&node, host, port, ally);
|
||||
defer driver.deinit();
|
||||
|
||||
try driver.run();
|
||||
}
|
||||
@@ -44,7 +44,7 @@ test "abc" {
|
||||
try golden.snap(
|
||||
@src(),
|
||||
\\.packet = .{
|
||||
\\ .header = .{.open, .normal, .none, .broadcast, .single, .announce, hops(0)},
|
||||
\\ .header = .{.open, .normal, .some, .broadcast, .single, .announce, hops(0)},
|
||||
\\ .endpoints = .normal{71cb75e4effb51744aa9877da2b9af56},
|
||||
\\ .context = .none,
|
||||
\\ .payload = .announce{
|
||||
@@ -53,7 +53,8 @@ test "abc" {
|
||||
\\ .name_hash = ca978112ca1bbdcafac2,
|
||||
\\ .noise = 9325ba36e2,
|
||||
\\ .timestamp = 000000000a,
|
||||
\\ .signature = c5fb72c740fd8cc1a1dd844c38039b361f5253060e6a4789d06f925fae58c5907ad29f590c73297ef7f929e4d3a79f1d9a22f6baded58784c3ad743d63c4b205,
|
||||
\\ .ratchet = 3cd8d216726b89248c7e1ae8d32e176dbb4c25dfbfa4edf2373f70c6c642ff85,
|
||||
\\ .signature = ca87af796f5ab949ea7e44e0e618a973f558fe81a676d536d022c47e300dba8164dae7a4e51d66b2b5d22ad5ef92b77558cc889710758bac97d1846ce34b6c0b,
|
||||
\\ .application_data = 6865726520697320736f6d65206170702064617461,
|
||||
\\ },
|
||||
\\}
|
||||
@@ -74,7 +75,7 @@ test "abc" {
|
||||
try golden.snap(
|
||||
@src(),
|
||||
\\.packet = .{
|
||||
\\ .header = .{.open, .transport, .none, .broadcast, .single, .announce, hops(1)},
|
||||
\\ .header = .{.open, .transport, .some, .broadcast, .single, .announce, hops(1)},
|
||||
\\ .endpoints = .transport{71cb75e4effb51744aa9877da2b9af56, f81ae61e99c1e826604cf1e5880c6847},
|
||||
\\ .context = .none,
|
||||
\\ .payload = .announce{
|
||||
@@ -83,7 +84,8 @@ test "abc" {
|
||||
\\ .name_hash = ca978112ca1bbdcafac2,
|
||||
\\ .noise = 9325ba36e2,
|
||||
\\ .timestamp = 000000000a,
|
||||
\\ .signature = c5fb72c740fd8cc1a1dd844c38039b361f5253060e6a4789d06f925fae58c5907ad29f590c73297ef7f929e4d3a79f1d9a22f6baded58784c3ad743d63c4b205,
|
||||
\\ .ratchet = 3cd8d216726b89248c7e1ae8d32e176dbb4c25dfbfa4edf2373f70c6c642ff85,
|
||||
\\ .signature = ca87af796f5ab949ea7e44e0e618a973f558fe81a676d536d022c47e300dba8164dae7a4e51d66b2b5d22ad5ef92b77558cc889710758bac97d1846ce34b6c0b,
|
||||
\\ .application_data = 6865726520697320736f6d65206170702064617461,
|
||||
\\ },
|
||||
\\}
|
||||
|
||||
@@ -136,7 +136,7 @@ pub fn addEndpoint(self: *Self, name: []const u8) !core.Endpoint {
|
||||
_ = try builder
|
||||
.setIdentity(identity)
|
||||
.setDirection(.in)
|
||||
.setMethod(.single)
|
||||
.setVariant(.single)
|
||||
.setApplicationName(name);
|
||||
|
||||
var endpoint = try builder.build();
|
||||
|
||||
Reference in New Issue
Block a user