Skip to documentation
SLOP

tiny.reticulum.crypto.hkdf

Reference tiny.reticulum crypto hkdf

Defined in crypto.

API (4)

Actions

Public operations.

Types and contracts

Public types and contracts.

Values and defaults

Public values and defaults.

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

Source

Called byCallsprivate sourcelib.reticulum.src.crypto.testexpectHkdftest sourcelib.reticulum.src.crypto.testtest: HKDF u16 maximum and maximum pl...test sourcelib.reticulum.src.crypto.test.test_Reticulum@...py:35-62 differential corpusprivate sourcelib.reticulum.src.identity.cipherdecryptWithKeyidentity.cipherencrypt+2 moreprivate sourcelib.reticulum.src.crypto.hkdfeffectiveSaltprivate sourcelib.reticulum.src.crypto.hkdfexpandprivate sourcelib.reticulum.src.crypto.hkdfoverlapscrypto.hmacsigncrypto.hkdfderive
Static calls · unresolved targets: 0 · external targets: 0.

Source: lib/reticulum/src/crypto/hkdf.zig

zig
const std = @import("std");const crypto = @import("root.zig");pub const hash_length: u8 = crypto.hmac.tag_length;pub const max_output_length: u16 = std.math.maxInt(u16);pub const HkdfError = error{    InvalidLength,    OutputTooLong,    EmptyKeyMaterial,    OutputTooSmall,    OverlappingBuffers,};/// Writes `length` derived bytes into `out` and returns them, so a caller turns/// a shared secret into exactly as many key bytes as it needs, following/// Reticulum@1.5.0 RNS/Cryptography/HKDF.py:35-62. The first stage signs the/// key material under the salt, and the second stage builds the output one/// 32-byte block at a time, each block signed over the block before it, then/// the context, then a counter byte that starts at one and wraps at 256. A salt/// the caller leaves out, or passes empty, becomes 32 zero bytes. The call/// returns `error.InvalidLength` for a length of zero, `error.OutputTooLong`/// past 65,535 bytes, `error.EmptyKeyMaterial` for empty key material,/// `error.OutputTooSmall` when `out` is shorter than the length, and/// `error.OverlappingBuffers` when the key material, the salt, or the context/// overlaps the output.pub fn derive(    length: u17,    key_material: []const u8,    salt: ?[]const u8,    context: ?[]const u8,    out: []u8,) HkdfError![]u8 {    if (length == 0) return error.InvalidLength;    if (length > max_output_length) return error.OutputTooLong;    if (key_material.len == 0) return error.EmptyKeyMaterial;    const output_length: usize = @intCast(length);    if (out.len < output_length) return error.OutputTooSmall;    const result = out[0..output_length];    if (overlaps(key_material, result)) return error.OverlappingBuffers;    if (salt) |value| if (overlaps(value, result)) return error.OverlappingBuffers;    if (context) |value| if (overlaps(value, result)) return error.OverlappingBuffers;    const zero_salt: [hash_length]u8 = @splat(0);    const selected_salt = effectiveSalt(salt, &zero_salt);    const selected_context = context orelse "";    const pseudorandom_key = crypto.hmac.sign(selected_salt, key_material);    expand(@intCast(length), pseudorandom_key, selected_context, result);    return result;}fn effectiveSalt(salt: ?[]const u8, zero_salt: *const [hash_length]u8) []const u8 {    const value = salt orelse return zero_salt;    if (value.len == 0) return zero_salt;    return value;}fn overlaps(input: []const u8, output: []u8) bool {    if (input.len == 0) return false;    const input_start = @intFromPtr(input.ptr);    const output_start = @intFromPtr(output.ptr);    const input_end = input_start + input.len;    const output_end = output_start + output.len;    return input_start < output_end and output_start < input_end;}fn expand(    length: u16,    pseudorandom_key: [hash_length]u8,    context: []const u8,    out: []u8,) void {    const output_length: usize = length;    std.debug.assert(output_length == out.len);    std.debug.assert(length <= max_output_length);    var previous: [hash_length]u8 = undefined;    var previous_length: usize = 0;    var written: usize = 0;    var block_index: u16 = 0;    while (written < output_length) : (block_index += 1) {        const counter = [1]u8{@intCast((block_index + 1) % 256)};        var signer = crypto.hmac.Signer.init(&pseudorandom_key);        signer.update(previous[0..previous_length]);        signer.update(context);        signer.update(&counter);        previous = signer.final();        previous_length = hash_length;        const take = @min(hash_length, output_length - written);        @memcpy(out[written..][0..take], previous[0..take]);        written += take;    }    std.debug.assert(written == output_length);}

Source: lib/reticulum/src/crypto/root.zig:46

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

Complete caller list for crypto.hkdf.derive

7 direct callers.

Audit

Definitions5
Public names5
Members5
Version26.7.0
Revisiondaab053ee433