lib/accy/src/kernel/library/random/block/threefry.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const random = @import("../root.zig");
2
3 const std = random.base.std;
4 const kernel = random.base.kernel;
5 const wordConstant = random.block.wordConstant;
6
7 pub const threefry_lanes: u64 = 2;
8 pub const threefry_default_rounds: u32 = 20;
9 pub const threefry_max_rounds: u32 = 32;
10
11 const threefry_parity: u32 = 0x1BD11BDA;
12 const threefry_rotations = [8]u5{ 13, 15, 26, 6, 17, 29, 16, 24 };
13
14 pub fn threefryBlock(rounds: u32, counter: [2]u32, key: [2]u32) [2]u32 {
15 const subkeys = [3]u32{ key[0], key[1], threefry_parity ^ key[0] ^ key[1] };
16 var x0 = counter[0] +% subkeys[0];
17 var x1 = counter[1] +% subkeys[1];
18 var round: u32 = 0;
19 while (round < rounds) : (round += 1) {
20 x0 +%= x1;
21 x1 = std.math.rotl(u32, x1, threefry_rotations[round % 8]);
22 x1 ^= x0;
23 if (round % 4 == 3) {
24 const injection = round / 4 + 1;
25 x0 +%= subkeys[injection % 3];
26 x1 +%= subkeys[(injection + 1) % 3];
27 x1 +%= injection;
28 }
29 }
30 return .{ x0, x1 };
31 }
32
33 pub fn rotateLeftWord(k: anytype, value: kernel.Value, amount: u5) !kernel.Value {
34 const left = try k.shl(value, try k.constantInt(.i32, amount));
35 const right = try k.ushr(value, try k.constantInt(.i32, 32 - @as(i64, amount)));
36 return k.or_(left, right);
37 }
38
39 pub fn threefryWords(
40 k: anytype,
41 rounds: u32,
42 counter: kernel.Value,
43 counter_fold: kernel.Value,
44 seed_lo: kernel.Value,
45 seed_hi: kernel.Value,
46 ) ![threefry_lanes]kernel.Value {
47 const parity = try wordConstant(k, threefry_parity);
48 const subkeys = [3]kernel.Value{
49 seed_lo,
50 seed_hi,
51 try k.xor(try k.xor(parity, seed_lo), seed_hi),
52 };
53 var x0 = try k.add(counter, subkeys[0]);
54 var x1 = try k.add(counter_fold, subkeys[1]);
55 var round: u32 = 0;
56 while (round < rounds) : (round += 1) {
57 x0 = try k.add(x0, x1);
58 x1 = try rotateLeftWord(k, x1, threefry_rotations[round % 8]);
59 x1 = try k.xor(x1, x0);
60 if (round % 4 == 3) {
61 const injection = round / 4 + 1;
62 x0 = try k.add(x0, subkeys[injection % 3]);
63 x1 = try k.add(x1, subkeys[(injection + 1) % 3]);
64 x1 = try k.add(x1, try k.constantInt(.i32, injection));
65 }
66 }
67 return .{ x0, x1 };
68 }