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 }