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.

ctrSlice

Counter mode with configurable counter position and size.

This extended version allows specifying where the counter is located within the IV block and how many bytes it occupies. This is useful for modes like AES-GCM-SIV which use a 32-bit counter at the beginning of the block.

@param counter_offset: Byte offset where the counter starts @param counter_size: Size of the counter in bytes

modes.ctrSlice
pub fn ctrSlice(
    comptime BlockCipher: anytype,
    block_cipher: BlockCipher,
    dst: []u8,
    src: []const u8,
    iv: [BlockCipher.block_length]u8,
    endian: std.builtin.Endian,
    comptime counter_offset: usize,
    comptime counter_size: usize,
) void

File

lib/std/crypto/modes.zig:25

Code

pub fn ctrSlice(
    comptime BlockCipher: anytype,
    block_cipher: BlockCipher,
    dst: []u8,
    src: []const u8,
    iv: [BlockCipher.block_length]u8,
    endian: std.builtin.Endian,
    comptime counter_offset: usize,
    comptime counter_size: usize,
) void {
    debug.assert(dst.len >= src.len);
    const block_length = BlockCipher.block_length;
    debug.assert(counter_offset + counter_size <= block_length);
    debug.assert(counter_size > 0 and counter_size <= block_length);

    var counterBlock = iv;
    var i: usize = 0;

    const CounterInt = @Int(.unsigned, counter_size * 8);

    const parallel_count = BlockCipher.block.parallel.optimal_parallel_blocks;
    const wide_block_length = parallel_count * block_length;
    var cnt_val = mem.readInt(CounterInt, counterBlock[counter_offset..][0..counter_size], endian);
    if (src.len >= wide_block_length) {
        var counters: [parallel_count * block_length]u8 = undefined;
        inline for (0..parallel_count) |j| {
            counters[j * block_length ..][0..block_length].* = iv;
        }
        while (i + wide_block_length <= src.len) : (i += wide_block_length) {
            comptime var j = 0;
            inline while (j < parallel_count) : (j += 1) {
                mem.writeInt(CounterInt, counters[j * block_length + counter_offset ..][0..counter_size], cnt_val +% j, endian);
            }
            cnt_val +%= parallel_count;
            block_cipher.xorWide(parallel_count, dst[i .. i + wide_block_length][0..wide_block_length], src[i .. i + wide_block_length][0..wide_block_length], counters);
        }
        mem.writeInt(CounterInt, counterBlock[counter_offset..][0..counter_size], cnt_val, endian);
    }
    while (i + block_length <= src.len) : (i += block_length) {
        block_cipher.xor(dst[i .. i + block_length][0..block_length], src[i .. i + block_length][0..block_length], counterBlock);
        cnt_val +%= 1;
        mem.writeInt(CounterInt, counterBlock[counter_offset..][0..counter_size], cnt_val, endian);
    }
    if (i < src.len) {
        var pad: [block_length]u8 = @splat(0);
        const src_slice = src[i..];
        @memcpy(pad[0..src_slice.len], src_slice);
        block_cipher.xor(&pad, &pad, counterBlock);
        const pad_slice = pad[0 .. src.len - i];
        @memcpy(dst[i..][0..pad_slice.len], pad_slice);
    }
}