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.

State256X

aegis.State256X
fn State256X(comptime degree: u7) type

File

lib/std/crypto/aegis.zig:361

Code

fn State256X(comptime degree: u7) type {
    return struct {
        const AesBlockVec = crypto.core.aes.BlockVec(degree);
        const State = @This();

        blocks: [6]AesBlockVec,

        const aes_block_length = AesBlockVec.block_length;
        const rate = aes_block_length;
        const alignment = AesBlockVec.native_word_size;

        fn init(key: [32]u8, nonce: [32]u8) State {
            const c1 = AesBlockVec.fromBytes(&repeat16u8(degree, .{ 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd }));
            const c2 = AesBlockVec.fromBytes(&repeat16u8(degree, .{ 0x0, 0x1, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 }));
            const key_block1 = AesBlockVec.fromBytes(&repeat16u8(degree, key[0..16].*));
            const key_block2 = AesBlockVec.fromBytes(&repeat16u8(degree, key[16..32].*));
            const nonce_block1 = AesBlockVec.fromBytes(&repeat16u8(degree, nonce[0..16].*));
            const nonce_block2 = AesBlockVec.fromBytes(&repeat16u8(degree, nonce[16..32].*));
            const kxn1 = key_block1.xorBlocks(nonce_block1);
            const kxn2 = key_block2.xorBlocks(nonce_block2);
            const blocks = [6]AesBlockVec{
                kxn1,
                kxn2,
                c1,
                c2,
                key_block1.xorBlocks(c2),
                key_block2.xorBlocks(c1),
            };
            var state = State{ .blocks = blocks };
            if (degree > 1) {
                const context_block = ctx: {
                    var contexts_bytes: [aes_block_length]u8 = @splat(0);
                    for (0..degree) |i| {
                        contexts_bytes[i * 16] = @intCast(i);
                        contexts_bytes[i * 16 + 1] = @intCast(degree - 1);
                    }
                    break :ctx AesBlockVec.fromBytes(&contexts_bytes);
                };
                for (0..4) |_| {
                    state.blocks[3] = state.blocks[3].xorBlocks(context_block);
                    state.blocks[5] = state.blocks[5].xorBlocks(context_block);
                    state.update(key_block1);
                    state.blocks[3] = state.blocks[3].xorBlocks(context_block);
                    state.blocks[5] = state.blocks[5].xorBlocks(context_block);
                    state.update(key_block2);
                    state.blocks[3] = state.blocks[3].xorBlocks(context_block);
                    state.blocks[5] = state.blocks[5].xorBlocks(context_block);
                    state.update(kxn1);
                    state.blocks[3] = state.blocks[3].xorBlocks(context_block);
                    state.blocks[5] = state.blocks[5].xorBlocks(context_block);
                    state.update(kxn2);
                }
            } else {
                for (0..4) |_| {
                    state.update(key_block1);
                    state.update(key_block2);
                    state.update(kxn1);
                    state.update(kxn2);
                }
            }
            return state;
        }

        fn update(state: *State, d: AesBlockVec) void {
            const blocks = &state.blocks;
            const tmp = blocks[5].encrypt(blocks[0]);
            comptime var i: usize = 5;
            inline while (i > 0) : (i -= 1) {
                blocks[i] = blocks[i - 1].encrypt(blocks[i]);
            }
            blocks[0] = tmp.xorBlocks(d);
        }

        fn absorb(state: *State, src: *const [rate]u8) void {
            const msg = AesBlockVec.fromBytes(src);
            state.update(msg);
        }

        fn enc(state: *State, dst: *[rate]u8, src: *const [rate]u8) void {
            const blocks = &state.blocks;
            const msg = AesBlockVec.fromBytes(src);
            var tmp = msg.xorBlocks(blocks[5]).xorBlocks(blocks[4]).xorBlocks(blocks[1]);
            tmp = tmp.xorBlocks(blocks[2].andBlocks(blocks[3]));
            dst.* = tmp.toBytes();
            state.update(msg);
        }

        fn dec(state: *State, dst: *[rate]u8, src: *const [rate]u8) void {
            const blocks = &state.blocks;
            var msg = AesBlockVec.fromBytes(src).xorBlocks(blocks[5]).xorBlocks(blocks[4]).xorBlocks(blocks[1]);
            msg = msg.xorBlocks(blocks[2].andBlocks(blocks[3]));
            dst.* = msg.toBytes();
            state.update(msg);
        }

        fn decLast(state: *State, dst: []u8, src: []const u8) void {
            const blocks = &state.blocks;
            const z = blocks[5].xorBlocks(blocks[4]).xorBlocks(blocks[1]).xorBlocks(blocks[2].andBlocks(blocks[3]));
            var pad = z.toBytes();
            for (pad[0..src.len], src) |*p, x| p.* ^= x;
            @memcpy(dst, pad[0..src.len]);
            @memset(pad[src.len..], 0);
            const msg = AesBlockVec.fromBytes(pad[0..]);
            state.update(msg);
        }

        fn finalize(state: *State, comptime tag_bits: u9, adlen: usize, mlen: usize) [tag_bits / 8]u8 {
            const blocks = &state.blocks;
            var sizes: [aes_block_length]u8 = undefined;
            mem.writeInt(u64, sizes[0..8], @as(u64, adlen) * 8, .little);
            mem.writeInt(u64, sizes[8..16], @as(u64, mlen) * 8, .little);
            for (1..degree) |i| {
                @memcpy(sizes[i * 16 ..][0..16], sizes[0..16]);
            }
            const tmp = AesBlockVec.fromBytes(&sizes).xorBlocks(blocks[3]);
            for (0..7) |_| {
                state.update(tmp);
            }
            switch (tag_bits) {
                128 => {
                    var tag_multi = blocks[0].xorBlocks(blocks[1]).xorBlocks(blocks[2]).xorBlocks(blocks[3]).xorBlocks(blocks[4]).xorBlocks(blocks[5]).toBytes();
                    var tag = tag_multi[0..16].*;
                    @memcpy(tag[0..], tag_multi[0..16]);
                    for (1..degree) |d| {
                        for (0..16) |i| {
                            tag[i] ^= tag_multi[d * 16 + i];
                        }
                    }
                    return tag;
                },
                256 => {
                    const tag_multi_1 = blocks[0].xorBlocks(blocks[1]).xorBlocks(blocks[2]).toBytes();
                    const tag_multi_2 = blocks[3].xorBlocks(blocks[4]).xorBlocks(blocks[5]).toBytes();
                    var tag = tag_multi_1[0..16].* ++ tag_multi_2[0..16].*;
                    for (1..degree) |d| {
                        for (0..16) |i| {
                            tag[i] ^= tag_multi_1[d * 16 + i];
                            tag[i + 16] ^= tag_multi_2[d * 16 + i];
                        }
                    }
                    return tag;
                },
                else => unreachable,
            }
        }

        fn finalizeMac(state: *State, comptime tag_bits: u9, datalen: usize) [tag_bits / 8]u8 {
            const blocks = &state.blocks;
            var sizes: [aes_block_length]u8 = undefined;
            mem.writeInt(u64, sizes[0..8], @as(u64, datalen) * 8, .little);
            mem.writeInt(u64, sizes[8..16], tag_bits, .little);
            for (1..degree) |i| {
                @memcpy(sizes[i * 16 ..][0..16], sizes[0..16]);
            }
            var t = blocks[3].xorBlocks(AesBlockVec.fromBytes(&sizes));
            for (0..7) |_| {
                state.update(t);
            }
            if (degree > 1) {
                var v: [rate]u8 = @splat(0);
                switch (tag_bits) {
                    128 => {
                        const tags = blocks[0].xorBlocks(blocks[1]).xorBlocks(blocks[2]).xorBlocks(blocks[3]).xorBlocks(blocks[4]).xorBlocks(blocks[5]).toBytes();
                        for (1..degree) |d| {
                            v[0..16].* = tags[d * 16 ..][0..16].*;
                            state.absorb(&v);
                        }
                    },
                    256 => {
                        const tags_0 = blocks[0].xorBlocks(blocks[1]).xorBlocks(blocks[2]).toBytes();
                        const tags_1 = blocks[3].xorBlocks(blocks[4]).xorBlocks(blocks[5]).toBytes();
                        for (1..degree) |d| {
                            v[0..16].* = tags_0[d * 16 ..][0..16].*;
                            state.absorb(&v);
                            v[0..16].* = tags_1[d * 16 ..][0..16].*;
                            state.absorb(&v);
                        }
                    },
                    else => unreachable,
                }
                mem.writeInt(u64, sizes[0..8], degree, .little);
                mem.writeInt(u64, sizes[8..16], tag_bits, .little);
                t = blocks[3].xorBlocks(AesBlockVec.fromBytes(&sizes));
                for (0..7) |_| {
                    state.update(t);
                }
            }
            switch (tag_bits) {
                128 => {
                    const tags = blocks[0].xorBlocks(blocks[1]).xorBlocks(blocks[2]).xorBlocks(blocks[3]).xorBlocks(blocks[4]).xorBlocks(blocks[5]).toBytes();
                    return tags[0..16].*;
                },
                256 => {
                    const tags_0 = blocks[0].xorBlocks(blocks[1]).xorBlocks(blocks[2]).toBytes();
                    const tags_1 = blocks[3].xorBlocks(blocks[4]).xorBlocks(blocks[5]).toBytes();
                    return tags_0[0..16].* ++ tags_1[0..16].*;
                },
                else => unreachable,
            }
        }
    };
}