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.

AsconCxof128

Ascon-CXOF128 as specified in NIST SP 800-232 Section 5

ascon.AsconCxof128
pub const AsconCxof128 = struct

File

lib/std/crypto/ascon.zig:787

Code

pub const AsconCxof128 = struct {
    pub const block_length = 8;
    pub const max_custom_length = 256; // 2048 bits

    st: AsconState,
    squeezed: bool,
    buf: [block_length]u8,
    buf_len: usize,

    pub const Options = struct { custom: []const u8 = "" };

    /// Initialize a new Ascon-CXOF128 customizable XOF.
    ///
    /// Parameters:
    ///   - options: Configuration with optional customization string
    ///     - custom: Customization string (max 256 bytes)
    ///
    /// Returns: An initialized AsconCxof128 instance
    ///
    /// Note: Different customization strings produce independent XOF instances
    pub fn init(options: Options) AsconCxof128 {
        debug.assert(options.custom.len <= max_custom_length);

        // IV for Ascon-CXOF128: 0x0000080000cc0004
        const iv: u64 = 0x0000080000cc0004;
        const words: [5]u64 = .{ iv, 0, 0, 0, 0 };
        var st = AsconState.initFromWords(words);
        st.permuteR(12);

        var self = AsconCxof128{ .st = st, .squeezed = false, .buf = @splat(0), .buf_len = 0 };

        // Process customization string - always process length and padding
        // First block: length of customization string
        const len_block = @as(u64, options.custom.len * 8); // Length in bits
        self.st.st[0] ^= len_block;
        self.st.permuteR(12);

        if (options.custom.len > 0) {
            // Process customization string blocks
            var i: usize = 0;
            while (i + 8 <= options.custom.len) : (i += 8) {
                self.st.addBytes(options.custom[i..][0..8]);
                self.st.permuteR(12);
            }

            // Process final partial block with padding
            if (i < options.custom.len) {
                var padded: [8]u8 = @splat(0);
                const remaining = options.custom.len - i;
                @memcpy(padded[0..remaining], options.custom[i..]);
                padded[remaining] = 0x01;
                self.st.addBytes(&padded);
                self.st.permuteR(12);
            } else {
                // Add padding block
                var padded: [8]u8 = @splat(0);
                padded[0] = 0x01;
                self.st.addBytes(&padded);
                self.st.permuteR(12);
            }
        } else {
            // Empty customization still needs padding
            var padded: [8]u8 = @splat(0);
            padded[0] = 0x01;
            self.st.addBytes(&padded);
            self.st.permuteR(12);
        }

        return self;
    }

    /// Hash a slice of bytes with customization and variable-length output.
    ///
    /// Parameters:
    ///   - bytes: Input data to hash
    ///   - out: Output buffer (can be any length)
    ///   - options: Configuration with optional customization string
    ///
    /// Note: Convenience function that combines init, update, and squeeze
    pub fn hash(bytes: []const u8, out: []u8, options: Options) void {
        var st = init(options);
        st.update(bytes);
        st.squeeze(out);
    }

    /// Update the CXOF state with additional data.
    ///
    /// Parameters:
    ///   - b: Data to absorb into the CXOF state
    ///
    /// Note: Cannot be called after squeeze() has been called
    pub fn update(self: *AsconCxof128, b: []const u8) void {
        debug.assert(!self.squeezed); // Cannot update after squeezing

        var i: usize = 0;

        if (self.buf_len > 0) {
            const to_fill = @min(block_length - self.buf_len, b.len);
            @memcpy(self.buf[self.buf_len..][0..to_fill], b[0..to_fill]);
            self.buf_len += to_fill;
            i += to_fill;
            if (self.buf_len == block_length) {
                self.st.addBytes(&self.buf);
                self.st.permuteR(12);
                self.buf_len = 0;
            }
        }

        while (i + block_length <= b.len) : (i += block_length) {
            self.st.addBytes(b[i..][0..block_length]);
            self.st.permuteR(12);
        }

        if (i < b.len) {
            self.buf_len = b.len - i;
            @memcpy(self.buf[0..self.buf_len], b[i..]);
        }
    }

    /// Squeeze output bytes from the customizable XOF.
    ///
    /// Parameters:
    ///   - out: Output buffer to fill with pseudorandom bytes
    ///
    /// Note: Can be called multiple times to generate more output.
    /// After first call, no more data can be absorbed with update().
    pub fn squeeze(self: *AsconCxof128, out: []u8) void {
        if (!self.squeezed) {
            var padded: [block_length]u8 = @splat(0);
            @memcpy(padded[0..self.buf_len], self.buf[0..self.buf_len]);
            padded[self.buf_len] = 0x01;
            self.st.addBytes(&padded);
            self.st.permuteR(12);
            self.squeezed = true;
        }

        var i: usize = 0;
        while (i < out.len) {
            const to_copy = @min(8, out.len - i);
            var block: [8]u8 = undefined;
            mem.writeInt(u64, &block, self.st.st[0], .little);
            @memcpy(out[i..][0..to_copy], block[0..to_copy]);
            i += to_copy;

            if (i < out.len) {
                self.st.permuteR(12);
            }
        }
    }
}