Skip to documentation
SLOP

tiny.reticulum.node.announce

Reference tiny.reticulum node announce

Defined in node.

API (1)

Actions

Public operations.

No direct callersNo direct callsnodeannounce
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallsnode.transitionrunprivate sourcelib.reticulum.src.node.announcebuildFrameprivate sourcelib.reticulum.src.node.announcefanoutForprivate sourcelib.reticulum.src.node.announcerotatingKeynode.outboundframeCountnode.outboundreserve+2 morenode.announcerun
Static calls · unresolved targets: 0 · external targets: 4.

Source: lib/reticulum/src/node/announce.zig

zig
const std = @import("std");const reticulum = @import("../root.zig");const destination = reticulum.destination;const identity = reticulum.identity;const node = reticulum.node;const wire = reticulum.wire;const timestamp_max: node.Seconds = std.math.maxInt(u40);fn needsRotation(ring: *const identity.Ring, now: node.Seconds) bool {    if (ring.count == 0) return true;    const latest = ring.latest_time orelse return true;    const deadline = std.math.add(node.Seconds, latest, identity.ratchet.reference_interval) catch        std.math.maxInt(node.Seconds);    return now > deadline;}fn randomHash(random: [5]u8, now: node.Seconds) [10]u8 {    std.debug.assert(now <= timestamp_max);    var result: [10]u8 = undefined;    @memcpy(result[0..5], &random);    std.mem.writeInt(u40, result[5..10], @intCast(now), .big);    return result;}fn rotatingKey(    node_owner: *node.Node,    identity_index: usize,    announce: node.ApplicationAnnounce,) node.StepError!?[32]u8 {    const binding = node_owner.ratchet_bindings[identity_index];    const ring = binding.ring orelse return null;    if (needsRotation(ring, announce.now)) {        const fresh_bytes = announce.fresh_rotating_key orelse return error.MissingEntropy;        var fresh = identity.Ratchet.fromBytes(fresh_bytes);        defer fresh.zero();        _ = ring.rotate(announce.now, identity.ratchet.reference_interval, fresh);    }    const latest = ring.latest() orelse return error.MissingEntropy;    return latest.publicBytes();}fn buildFrame(    node_owner: *node.Node,    value: node.ApplicationAnnounce,    private: *const identity.Private,    name_hash: [10]u8,    rotating_public: ?[32]u8,) node.StepError![]const u8 {    const payload_start: usize = wire.header_one_bytes;    const payload = destination.announce.build(.{        .destination_hash = value.destination,        .name_hash = name_hash,        .random_hash = randomHash(value.random, value.now),        .rotating_public_key = rotating_public,        .app_data = value.app_data,    }, private, node_owner.scratch[payload_start..]) catch |err| switch (err) {        error.AppDataTooLong => return error.AppDataTooLong,        error.OutputTooSmall => return error.PacketTooLarge,    };    return wire.encode(.{        .ifac = 0,        .header = .one,        .context_flag = @intFromBool(rotating_public != null),        .transport = .broadcast,        .destination_type = .single,        .packet_type = .announce,        .hops = 0,        .transport_id = null,        .destination = value.destination,        .context = if (value.path_response == null) .none else .path_response,        .payload = payload,    }, node_owner.scratch) catch return error.PacketTooLarge;}fn fanoutFor(value: node.ApplicationAnnounce) node.outbound.Fanout {    const index = value.path_response orelse return .all;    return .{ .one = index };}/// Announces one of the node's own destinations, so every node that hears it learns the/// destination's public keys and how far away it sits, as Reticulum@1.5.0/// RNS/Destination.py:228-315 builds it. The same call answers a path request. With a carrier named/// to answer on, the announce goes out on that carrier alone, following Reticulum@1.5.0/// RNS/Transport.py:3379-3382, and otherwise it goes out on every outgoing carrier. The announce/// stamps the caller's instant into five of its ten random bytes, so an instant past 2^40 - 1/// seconds returns `error.TimestampOutOfRange`. A destination hash with no registration behind it/// returns `error.UnknownDestination`, and a registration of another kind, or one that names no/// local identity, returns `error.InvalidDestination`. A fanout that reaches no outgoing carrier/// returns `error.NoOutgoingCarrier`. With a rotating-key ring bound to the destination's identity,/// the announce carries a rotating public key, and the node rotates a fresh one in when the ring is/// empty or its newest key is more than thirty minutes old. A rotation with no fresh key from the/// caller returns `error.MissingEntropy`. The node remembers the rotating key it published and/// stores the announce's packet hash, so the same announce coming back is a duplicate.pub fn run(node_owner: *node.Node, value: node.ApplicationAnnounce) node.StepError!void {    if (value.now > timestamp_max) return error.TimestampOutOfRange;    const entry = node_owner.destinations.find(value.destination) orelse        return error.UnknownDestination;    if (entry.kind != .single) return error.InvalidDestination;    const identity_index = entry.identity_index orelse return error.InvalidDestination;    const private = node_owner.identityAt(identity_index) orelse return error.InvalidDestination;    const fanout = fanoutFor(value);    const carriers = node.outbound.frameCount(node_owner, fanout);    if (carriers == 0) return error.NoOutgoingCarrier;    try node.outbound.reserve(node_owner, carriers, carriers);    const rotating_public = try rotatingKey(node_owner, identity_index, value);    const frame = try buildFrame(node_owner, value, private, entry.name_hash, rotating_public);    if (rotating_public) |public_key| node_owner.known_ratchets.remember(.{        .destination_hash = value.destination,        .public_key = public_key,        .received = value.now,    });    const packet_hash = wire.hash.full(frame) catch unreachable;    _ = node_owner.duplicate_hashes.insert(packet_hash);    try node.outbound.transmit(node_owner, fanout, frame);}

Source: lib/reticulum/src/node/root.zig:74

zig
pub const announce = @import("announce.zig");

Complete call list for node.announce.run

7 direct calls.

Audit

Definitions2
Public names2
Members0
Version26.7.0
Revisiondaab053ee433