Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion core/Node.zig
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const Identity = @import("crypto.zig").Identity;
const Packet = @import("packet.zig").Packet;
const PacketFactory = @import("packet.zig").Factory;
const PacketFilter = @import("packet.zig").Filter;
const Ratchets = @import("Ratchets.zig");
const Routes = @import("Routes.zig");
const Name = @import("endpoint/Name.zig");
const ThreadSafeFifo = @import("internal/ThreadSafeFifo.zig").ThreadSafeFifo;
Expand All @@ -33,6 +34,7 @@ system: System,
options: Options,
endpoints: Endpoints,
interfaces: Interfaces,
ratchets: Ratchets,
routes: Routes,
packet_filter: PacketFilter,

Expand All @@ -47,8 +49,9 @@ pub fn init(ally: Allocator, system: *System, identity: ?Identity, options: Opti
defer main_endpoint.deinit();
const endpoints = try Endpoints.init(ally, &main_endpoint);
const interfaces = Interfaces.init(ally, system.*);
const ratchets = Ratchets.init(ally, &system.rng);
const routes = Routes.init(ally);
const packet_filter_capacity = if (builtin.target.os.tag == .freestanding) 2048 else 1_000_000;
const packet_filter_capacity = if (builtin.target.os.tag == .freestanding and builtin.cpu.arch != .wasm32) 2048 else 32768;
const packet_filter = try PacketFilter.init(ally, packet_filter_capacity);

return .{
Expand All @@ -58,6 +61,7 @@ pub fn init(ally: Allocator, system: *System, identity: ?Identity, options: Opti
.options = options,
.endpoints = endpoints,
.interfaces = interfaces,
.ratchets = ratchets,
.routes = routes,
.packet_filter = packet_filter,
};
Expand Down
82 changes: 82 additions & 0 deletions core/Ratchets.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
const builtin = @import("builtin");
const std = @import("std");
const crypto = @import("crypto.zig");

const Allocator = std.mem.Allocator;
const Hash = crypto.Hash;
const Ratchet = [32]u8;
const System = @import("System.zig");

const Self = @This();

const Entry = struct {
ratchets: std.fifo.LinearFifo(Ratchet, .Dynamic),
last_rotation_time: u64,
};

const max_ratchets = if (builtin.os.tag == .freestanding) 32 else 256;
const rotation_period = 30 * std.time.us_per_min;

ally: Allocator,
entries: std.StringArrayHashMap(Entry),
rng: *System.Rng,

pub fn init(ally: Allocator, rng: *System.Rng) Self {
return Self{
.ally = ally,
.entries = std.StringArrayHashMap(Entry).init(ally),
.rng = rng,
};
}

pub fn add(self: *Self, endpoint: Hash.Short, now: u64) !Ratchet {
if (self.entries.contains(&endpoint)) {
return error.EntryAlreadyExists;
}

const key = try self.ally.dupe(u8, &endpoint);

try self.entries.put(key, .{
.ratchets = self.ally,
.last_rotation_time = now,
});

const ratchet = try self.getRatchet(&endpoint, now) orelse unreachable;
return ratchet;
}

pub fn getRatchet(self: *Self, endpoint: Hash.Short, now: u64) !?Ratchet {
if (self.entries.getPtr(&endpoint)) |entry| {
const needs_rotating = now - entry.last_rotation_time >= rotation_period;

if (needs_rotating) {
var seed: [crypto.X25519.seed_length]u8 = undefined;
self.rng.bytes(&seed);

const ratchet = try crypto.X25519.KeyPair.generateDeterministic(seed);

if (entry.ratchets.count >= max_ratchets) {
entry.ratchets.discard(1);
}

entry.ratchets.writeItem(ratchet.public_key);
entry.last_rotation_time = now;
}

return entry.ratchets.peekItem(entry.ratchets.count - 1);
}

return null;
}

pub fn deinit(self: *Self) void {
var entries = self.entries.iterator();

while (entries.next()) |entry| {
self.ally.free(entry.key_ptr.*);
entry.value_ptr.ratchets.deinit();
}

self.entries.deinit();
self.* = undefined;
}
Loading