Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

ktSingleThreaded

Generic single-threaded implementation

kangarootwelve.ktSingleThreaded
fn ktSingleThreaded(comptime Variant: type, view: *const MultiSliceView, total_len: usize, output: []u8) void

File

lib/std/crypto/kangarootwelve.zig:675

Code

fn ktSingleThreaded(comptime Variant: type, view: *const MultiSliceView, total_len: usize, output: []u8) void {
    const cv_size = Variant.cv_size;
    const StateType = Variant.StateType;

    // Initialize streaming TurboSHAKE state for final node (delimiter 0x06 is set in the type)
    var final_state = StateType.init(.{});

    // Absorb first B bytes from input
    var first_b_buffer: [chunk_size]u8 = undefined;
    if (view.tryGetSlice(0, chunk_size)) |first_chunk| {
        final_state.update(first_chunk);
    } else {
        view.copyRange(0, chunk_size, &first_b_buffer);
        final_state.update(&first_b_buffer);
    }

    // Absorb padding bytes (8 bytes: 0x03 followed by 7 zeros)
    const padding = [_]u8{ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    final_state.update(&padding);

    var j: usize = chunk_size;
    var n: usize = 0;

    // Temporary buffers for boundary-spanning leaves and CV computation
    var leaf_buffer: [chunk_size * 8]u8 align(cache_line_size) = undefined;
    var cv_buffer: [64]u8 = undefined; // Max CV size is 64 bytes

    // Process leaves in SIMD batches (8x, 4x, 2x)
    inline for ([_]usize{ 8, 4, 2 }) |batch_size| {
        while (optimal_vector_len >= batch_size and j + batch_size * chunk_size <= total_len) {
            processAndAbsorbNLeaves(Variant, batch_size, view, j, &leaf_buffer, &final_state);
            j += batch_size * chunk_size;
            n += batch_size;
        }
    }

    // Process remaining leaves one at a time
    while (j < total_len) {
        const chunk_len = @min(chunk_size, total_len - j);
        if (view.tryGetSlice(j, j + chunk_len)) |leaf_data| {
            const cv_slice = MultiSliceView.init(leaf_data, &[_]u8{}, &[_]u8{});
            Variant.turboShakeToBuffer(&cv_slice, 0x0B, cv_buffer[0..cv_size]);
            final_state.update(cv_buffer[0..cv_size]); // Absorb CV immediately
        } else {
            view.copyRange(j, j + chunk_len, leaf_buffer[0..chunk_len]);
            const cv_slice = MultiSliceView.init(leaf_buffer[0..chunk_len], &[_]u8{}, &[_]u8{});
            Variant.turboShakeToBuffer(&cv_slice, 0x0B, cv_buffer[0..cv_size]);
            final_state.update(cv_buffer[0..cv_size]);
        }
        j += chunk_size;
        n += 1;
    }

    // Absorb right_encode(n) and terminator
    const n_enc = rightEncode(n);
    final_state.update(n_enc.slice());
    const terminator = [_]u8{ 0xFF, 0xFF };
    final_state.update(&terminator);

    // Finalize and squeeze output
    final_state.final(output);
}