| ... | ... | @@ -22,19 +22,15 @@ fn Rp(a: usize, b: usize, c: usize, d: usize) QuarterRound { |
| 22 | 22 | }; |
| 23 | 23 | } |
| 24 | 24 | |
| 25 | | fn rotate(a: u32, b: u5) u32 { |
| 26 | | return ((a << b) | |
| 27 | | (a >> @intCast(u5, (32 - @intCast(u6, b)))) |
| 28 | | ); |
| 29 | | } |
| 30 | | |
| 31 | 25 | // The chacha family of ciphers are based on the salsa family. |
| 32 | | fn salsa20_wordtobyte(input: [16]u32) [64]u8 { |
| 26 | fn salsa20_wordtobyte(out: []u8, input: [16]u32) void { |
| 27 | assert(out.len >= 64); |
| 28 | |
| 33 | 29 | var x: [16]u32 = undefined; |
| 34 | | var out: [64]u8 = undefined; |
| 35 | 30 | |
| 36 | 31 | for (x) |_, i| |
| 37 | 32 | x[i] = input[i]; |
| 33 | |
| 38 | 34 | const rounds = comptime []QuarterRound{ |
| 39 | 35 | Rp( 0, 4, 8,12), |
| 40 | 36 | Rp( 1, 5, 9,13), |
| ... | ... | @@ -45,20 +41,21 @@ fn salsa20_wordtobyte(input: [16]u32) [64]u8 { |
| 45 | 41 | Rp( 2, 7, 8,13), |
| 46 | 42 | Rp( 3, 4, 9,14), |
| 47 | 43 | }; |
| 48 | | comptime var j: usize = 20; |
| 49 | | inline while (j > 0) : (j -=2) { |
| 50 | | for (rounds) |r| { |
| 51 | | x[r.a] +%= x[r.b]; x[r.d] = rotate(x[r.d] ^ x[r.a], 16); |
| 52 | | x[r.c] +%= x[r.d]; x[r.b] = rotate(x[r.b] ^ x[r.c], 12); |
| 53 | | x[r.a] +%= x[r.b]; x[r.d] = rotate(x[r.d] ^ x[r.a], 8); |
| 54 | | x[r.c] +%= x[r.d]; x[r.b] = rotate(x[r.b] ^ x[r.c], 7); |
| 44 | |
| 45 | comptime var j: usize = 0; |
| 46 | inline while (j < 20) : (j += 2) { |
| 47 | // two-round cycles |
| 48 | inline for (rounds) |r| { |
| 49 | x[r.a] +%= x[r.b]; x[r.d] = std.math.rotl(u32, x[r.d] ^ x[r.a], u32(16)); |
| 50 | x[r.c] +%= x[r.d]; x[r.b] = std.math.rotl(u32, x[r.b] ^ x[r.c], u32(12)); |
| 51 | x[r.a] +%= x[r.b]; x[r.d] = std.math.rotl(u32, x[r.d] ^ x[r.a], u32(8)); |
| 52 | x[r.c] +%= x[r.d]; x[r.b] = std.math.rotl(u32, x[r.b] ^ x[r.c], u32(7)); |
| 55 | 53 | } |
| 56 | 54 | } |
| 57 | | for (x) |_, i| |
| 58 | | x[i] +%= input[i]; |
| 59 | | for (x) |_, i| |
| 60 | | mem.writeInt(out[4 * i .. 4 * i + 4], x[i], builtin.Endian.Little); |
| 61 | | return out; |
| 55 | |
| 56 | for (x) |_, i| { |
| 57 | mem.writeInt(out[4 * i .. 4 * i + 4], x[i] +% input[i], builtin.Endian.Little); |
| 58 | } |
| 62 | 59 | } |
| 63 | 60 | |
| 64 | 61 | fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) void { |
| ... | ... | @@ -73,13 +70,14 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo |
| 73 | 70 | mem.readIntLE(u32, c[8..12]), |
| 74 | 71 | mem.readIntLE(u32, c[12..16]), |
| 75 | 72 | }; |
| 76 | | |
| 73 | |
| 77 | 74 | mem.copy(u32, ctx[0..], constant_le[0..4]); |
| 78 | 75 | mem.copy(u32, ctx[4..12], key[0..8]); |
| 79 | 76 | mem.copy(u32, ctx[12..16], counter[0..4]); |
| 80 | 77 | |
| 81 | 78 | while (true) { |
| 82 | | var buf = salsa20_wordtobyte(ctx); |
| 79 | var buf: [64]u8 = undefined; |
| 80 | salsa20_wordtobyte(buf[0..], ctx); |
| 83 | 81 | |
| 84 | 82 | if (remaining < 64) { |
| 85 | 83 | var i: usize = 0; |
| ... | ... | @@ -88,8 +86,8 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo |
| 88 | 86 | return; |
| 89 | 87 | } |
| 90 | 88 | |
| 91 | | comptime var i: usize = 0; |
| 92 | | inline while (i < 64) : (i += 1) |
| 89 | var i: usize = 0; |
| 90 | while (i < 64) : (i += 1) |
| 93 | 91 | out[cursor + i] = in[cursor + i] ^ buf[i]; |
| 94 | 92 | |
| 95 | 93 | cursor += 64; |