feature. See also
. The project being documented here (as the example) is the Zig library itself.
salsa20.SalsaNonVecImpl
fn SalsaNonVecImpl(comptime rounds: comptime_int) type
File
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;
}
};
}