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.

SalsaNonVecImpl

salsa20.SalsaNonVecImpl
fn SalsaNonVecImpl(comptime rounds: comptime_int) type

File

lib/std/crypto/salsa20.zig:179

Code

fn SalsaNonVecImpl(comptime rounds: comptime_int) type {
    return struct {
        const BlockVec = [16]u32;

        fn initContext(key: [8]u32, d: [4]u32) BlockVec {
            const c = "expand 32-byte k";
            const constant_le = comptime [4]u32{
                mem.readInt(u32, c[0..4], .little),
                mem.readInt(u32, c[4..8], .little),
                mem.readInt(u32, c[8..12], .little),
                mem.readInt(u32, c[12..16], .little),
            };
            return BlockVec{
                constant_le[0], key[0],         key[1],         key[2],
                key[3],         constant_le[1], d[0],           d[1],
                d[2],           d[3],           constant_le[2], key[4],
                key[5],         key[6],         key[7],         constant_le[3],
            };
        }

        const QuarterRound = struct {
            a: usize,
            b: usize,
            c: usize,
            d: u6,
        };

        fn Rp(a: usize, b: usize, c: usize, d: u6) QuarterRound {
            return QuarterRound{
                .a = a,
                .b = b,
                .c = c,
                .d = d,
            };
        }

        fn salsaCore(x: *BlockVec, input: BlockVec, comptime feedback: bool) void {
            const arx_steps = comptime [_]QuarterRound{
                Rp(4, 0, 12, 7),   Rp(8, 4, 0, 9),    Rp(12, 8, 4, 13),   Rp(0, 12, 8, 18),
                Rp(9, 5, 1, 7),    Rp(13, 9, 5, 9),   Rp(1, 13, 9, 13),   Rp(5, 1, 13, 18),
                Rp(14, 10, 6, 7),  Rp(2, 14, 10, 9),  Rp(6, 2, 14, 13),   Rp(10, 6, 2, 18),
                Rp(3, 15, 11, 7),  Rp(7, 3, 15, 9),   Rp(11, 7, 3, 13),   Rp(15, 11, 7, 18),
                Rp(1, 0, 3, 7),    Rp(2, 1, 0, 9),    Rp(3, 2, 1, 13),    Rp(0, 3, 2, 18),
                Rp(6, 5, 4, 7),    Rp(7, 6, 5, 9),    Rp(4, 7, 6, 13),    Rp(5, 4, 7, 18),
                Rp(11, 10, 9, 7),  Rp(8, 11, 10, 9),  Rp(9, 8, 11, 13),   Rp(10, 9, 8, 18),
                Rp(12, 15, 14, 7), Rp(13, 12, 15, 9), Rp(14, 13, 12, 13), Rp(15, 14, 13, 18),
            };
            x.* = input;
            var j: usize = 0;
            while (j < rounds) : (j += 2) {
                inline for (arx_steps) |r| {
                    x[r.a] ^= math.rotl(u32, x[r.b] +% x[r.c], r.d);
                }
            }
            if (feedback) {
                j = 0;
                while (j < 16) : (j += 1) {
                    x[j] +%= input[j];
                }
            }
        }

        fn hashToBytes(out: *[64]u8, x: BlockVec) void {
            for (x, 0..) |w, i| {
                mem.writeInt(u32, out[i * 4 ..][0..4], w, .little);
            }
        }

        fn salsaXor(out: []u8, in: []const u8, key: [8]u32, d: [4]u32) void {
            var ctx = initContext(key, d);
            var x: BlockVec = undefined;
            var buf: [64]u8 = undefined;
            var i: usize = 0;
            while (i + 64 <= in.len) : (i += 64) {
                salsaCore(x[0..], ctx, true);
                hashToBytes(buf[0..], x);
                var xout = out[i..];
                const xin = in[i..];
                var j: usize = 0;
                while (j < 64) : (j += 1) {
                    xout[j] = xin[j];
                }
                j = 0;
                while (j < 64) : (j += 1) {
                    xout[j] ^= buf[j];
                }
                const ov = @addWithOverflow(ctx[8], 1);
                ctx[8] = ov[0];
                ctx[9] += ov[1];
            }
            if (i < in.len) {
                salsaCore(x[0..], ctx, true);
                hashToBytes(buf[0..], x);

                var xout = out[i..];
                const xin = in[i..];
                var j: usize = 0;
                while (j < in.len % 64) : (j += 1) {
                    xout[j] = xin[j] ^ buf[j];
                }
            }
        }

        fn hsalsa(input: [16]u8, key: [32]u8) [32]u8 {
            var c: [4]u32 = undefined;
            for (c, 0..) |_, i| {
                c[i] = mem.readInt(u32, input[4 * i ..][0..4], .little);
            }
            const ctx = initContext(keyToWords(key), c);
            var x: BlockVec = undefined;
            salsaCore(x[0..], ctx, false);
            var out: [32]u8 = undefined;
            mem.writeInt(u32, out[0..4], x[0], .little);
            mem.writeInt(u32, out[4..8], x[5], .little);
            mem.writeInt(u32, out[8..12], x[10], .little);
            mem.writeInt(u32, out[12..16], x[15], .little);
            mem.writeInt(u32, out[16..20], x[6], .little);
            mem.writeInt(u32, out[20..24], x[7], .little);
            mem.writeInt(u32, out[24..28], x[8], .little);
            mem.writeInt(u32, out[28..32], x[9], .little);
            return out;
        }
    };
}