tiny.reticulum.identity
Defined in tiny.reticulum.
The key material behind one Reticulum address and everything that material does: name itself, sign, check a signature, seal a payload for a peer, open what arrives, and roll a short-lived key forward.
API (29)
Actions
Public operations.
BorrowedPublic.fromBytesBorrowedPublic.hash: Returns the first 16 bytes of the SHA-256 digest of the 64 public bytes, which names the identity inside a destination name, following Reticulum@1.5.0 RNS/Identity.py:784-786.BorrowedPublic.toBytesBorrowedPublic.validate: Returns whether an Ed25519 signature over a message checks out under the identity's signing half, following Reticulum@1.5.0 RNS/Identity.py:925.Private.fromBytesPrivate.hashPrivate.publicPrivate.publicBytesPrivate.signPrivate.toBytesPrivate.zeroPublic.borrowedPublic.fromBytesPublic.hashPublic.toBytesPublic.validatePublic.zero
Types and contracts
Public types and contracts.
BorrowedPublic: A view of 64 public bytes the caller already holds, which hashes and checks signatures where the bytes lie.KeyBytesPrivate: The 64 private bytes behind one identity, an X25519 secret followed by an Ed25519 seed, following Reticulum@1.5.0 RNS/Identity.py:59-62,624,727,737-754.Public: The 64 public bytes of one identity, an X25519 public key followed by an Ed25519 public key, following Reticulum@1.5.0 RNS/Identity.py:59-62,730-735,766-778.Ratchet: One retained X25519 private key.Ring: The caller's storage for a destination's retained keys, held newest first.RotatingSeconds
Namespaces
Public namespaces.
Values and defaults
Public values and defaults.
key_bytes: 64 bytes, the width of a Reticulum key value, which holds an X25519 half followed by an Ed25519 half, following Reticulum@1.5.0 RNS/Identity.py:59-62.
Source
Source: lib/reticulum/src/identity/key.zig:102
zig
/// A view of 64 public bytes the caller already holds, which hashes and checks/// signatures where the bytes lie. The view copies nothing, so the bytes it/// points at have to outlive it.pub const BorrowedPublic = struct { bytes: *const KeyBytes, pub fn fromBytes(bytes: *const KeyBytes) BorrowedPublic { return .{ .bytes = bytes }; } pub fn toBytes(self: BorrowedPublic) KeyBytes { return self.bytes.*; } /// Returns the first 16 bytes of the SHA-256 digest of the 64 public bytes, /// which names the identity inside a destination name, following /// Reticulum@1.5.0 RNS/Identity.py:784-786. pub fn hash(self: BorrowedPublic) [reticulum.hash.truncated_bytes]u8 { return reticulum.hash.truncated(self.bytes[0..key_bytes]); } /// Returns whether an Ed25519 signature over a message checks out under the /// identity's signing half, following Reticulum@1.5.0 RNS/Identity.py:925. /// Public bytes that form no valid Ed25519 point give false. pub fn validate(self: BorrowedPublic, signature: [64]u8, message: []const u8) bool { const signing = Ed25519.PublicKey.fromBytes( self.bytes[half_bytes..key_bytes].*, ) catch return false; const encoded = Ed25519.Signature.fromBytes(signature); encoded.verify(message, signing) catch return false; return true; }};Source: lib/reticulum/src/identity/key.zig:22
zig
/// The 64 private bytes behind one identity, an X25519 secret followed by an/// Ed25519 seed, following Reticulum@1.5.0/// RNS/Identity.py:59-62,624,727,737-754. The public bytes, the identity hash,/// and every signature derive from these. The value holds the bytes inline, so/// a copy is a second copy of the secret, and the caller that wants them gone/// keeps one instance and erases it.pub const Private = struct { bytes: KeyBytes, pub fn fromBytes(bytes: KeyBytes) Private { return .{ .bytes = bytes }; } pub fn zero(self: *Private) void { std.crypto.secureZero(u8, &self.bytes); } pub fn toBytes(self: *const Private) KeyBytes { return self.bytes; } pub fn publicBytes(self: *const Private) KeyBytes { const encryption = X25519.recoverPublicKey(self.bytes[0..half_bytes].*) catch unreachable; const signing = Ed25519.KeyPair.generateDeterministic( self.bytes[half_bytes..key_bytes].*, ) catch unreachable; var result: KeyBytes = undefined; result[0..half_bytes].* = encryption; result[half_bytes..key_bytes].* = signing.public_key.toBytes(); return result; } pub fn public(self: *const Private) Public { return Public.fromBytes(self.publicBytes()); } pub fn hash(self: *const Private) [reticulum.hash.truncated_bytes]u8 { return reticulum.hash.truncated(&self.publicBytes()); } pub fn sign(self: *const Private, message: []const u8) [64]u8 { const signing = Ed25519.KeyPair.generateDeterministic( self.bytes[half_bytes..key_bytes].*, ) catch unreachable; const signature = signing.sign(message, null) catch unreachable; return signature.toBytes(); }};Source: lib/reticulum/src/identity/key.zig:71
zig
/// The 64 public bytes of one identity, an X25519 public key followed by an/// Ed25519 public key, following Reticulum@1.5.0/// RNS/Identity.py:59-62,730-735,766-778. The value holds the bytes inline, so/// a copy is a second copy, and the caller that wants them gone keeps one/// instance and erases it.pub const Public = struct { bytes: KeyBytes, pub fn fromBytes(bytes: KeyBytes) Public { return .{ .bytes = bytes }; } pub fn zero(self: *Public) void { std.crypto.secureZero(u8, &self.bytes); } pub fn toBytes(self: *const Public) KeyBytes { return self.bytes; } pub fn borrowed(self: *const Public) BorrowedPublic { return BorrowedPublic.fromBytes(&self.bytes); } pub fn hash(self: *const Public) [reticulum.hash.truncated_bytes]u8 { return self.borrowed().hash(); } pub fn validate(self: *const Public, signature: [64]u8, message: []const u8) bool { return self.borrowed().validate(signature, message); }};Source: lib/reticulum/src/identity/key.zig:14
zig
pub const KeyBytes = [key_bytes]u8;Source: lib/reticulum/src/identity/key.zig:10
zig
/// 64 bytes, the width of a Reticulum key value, which holds an X25519 half/// followed by an Ed25519 half, following Reticulum@1.5.0/// RNS/Identity.py:59-62.pub const key_bytes: usize = 64;Source: lib/reticulum/src/identity/root.zig
zig
//! The key material behind one Reticulum address and everything that material//! does: name itself, sign, check a signature, seal a payload for a peer, open//! what arrives, and roll a short-lived key forward. An address on this network//! is a hash over a dotted name and the owner's public key, so the keys here//! make an address reachable by its owner alone.//!//! Whoever holds these bytes has to be the only party that can read what is//! addressed to the name and the only one that can sign for it. The code runs//! where memory is fixed before the program starts, so key values are plain//! arrays and every store takes its size from the caller. A node also has to//! remember what it learned about other parties from their announcements, under//! the same fixed memory.//!//! Key bytes that travel by value leave copies the owner has no way to reach,//! so erasing one copy leaves the rest. One key pair that never changes leaves//! every message ever addressed to it readable once those bytes leak. The//! sender picks which of a party's keys it encrypts to, so the receiver has to//! work out which one was used before it can read anything.//!//! The subtree follows Reticulum 1.5.0, the reference implementation, pinned to//! one upstream commit by the package README and the generated conformance//! corpus. What it takes is the key layout of Reticulum@1.5.0//! RNS/Identity.py:59-62, the encryption transcript of Reticulum@1.5.0//! RNS/Identity.py:804-836, the decryption order of Reticulum@1.5.0//! RNS/Identity.py:849-907, and the rotation rule of Reticulum@1.5.0//! RNS/Destination.py:206-243. The package generates identity vectors from that//! release and replays them in tests, so each of those claims is checkable from//! this tree.//!//! A party's key material, private or public (*identity*), is one 64-byte value//! the caller owns, and a caller that needs the bytes gone keeps a single//! instance and erases it in place. A third form borrows 64 public bytes the//! caller already holds, so checking a received announcement needs no copy of//! the key out of the payload. The short-lived keys a party has published//! (*rotating keys*) live newest first in one block of caller storage, which is//! zeroed when it is taken and again when it is handed back. Decryption walks//! the rotating keys a party keeps after it stops publishing them (*retained//! keys*) in the order the caller gave, falls back to the identity key, and//! reports which retained key opened the message. Every shared secret and//! derived key is erased before the call that made it returns. The subtree//! names its pieces: the key pairs, encryption and decryption, rotating keys//! and the ring that holds them, and what the node remembers about other//! parties.const key = @import("key.zig");const ratchet_module = @import("ratchet.zig");pub const Private = key.Private;pub const Public = key.Public;pub const BorrowedPublic = key.BorrowedPublic;pub const key_bytes = key.key_bytes;pub const KeyBytes = key.KeyBytes;pub const Rotating = @import("rotating.zig").Rotating;pub const cipher = @import("cipher.zig");pub const ratchet = ratchet_module;pub const Ratchet = ratchet_module.Ratchet;pub const Ring = ratchet_module.Ring;pub const Seconds = ratchet_module.Seconds;pub const known = @import("known.zig");Source: lib/reticulum/src/root.zig:63
zig
pub const identity = @import("identity/root.zig");Audit
| Definitions | 23 |
|---|---|
| Public names | 23 |
| Members | 3 |
| Version | 26.7.0 |
| Revision | daab053ee433 |