lib/accy/src/kernel/library/random/block/philox.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const random = @import("../root.zig");
2
3 const kernel = random.base.kernel;
4 const wordConstant = random.block.wordConstant;
5
6 pub const philox_lanes: u64 = 4;
7 pub const philox_default_rounds: u32 = 10;
8 pub const philox_max_rounds: u32 = 16;
9
10 const philox_m0: u32 = 0xD2511F53;
11 const philox_m1: u32 = 0xCD9E8D57;
12 const philox_w0: u32 = 0x9E3779B9;
13 const philox_w1: u32 = 0xBB67AE85;
14
15 pub fn philoxBlock(rounds: u32, counter: [4]u32, key: [2]u32) [4]u32 {
16 var state = counter;
17 var bumped = key;
18 var round: u32 = 0;
19 while (round < rounds) : (round += 1) {
20 if (round > 0) {
21 bumped[0] +%= philox_w0;
22 bumped[1] +%= philox_w1;
23 }
24 const product0 = @as(u64, philox_m0) * @as(u64, state[0]);
25 const product1 = @as(u64, philox_m1) * @as(u64, state[2]);
26 const hi0: u32 = @truncate(product0 >> 32);
27 const lo0: u32 = @truncate(product0);
28 const hi1: u32 = @truncate(product1 >> 32);
29 const lo1: u32 = @truncate(product1);
30 state = .{ hi1 ^ state[1] ^ bumped[0], lo1, hi0 ^ state[3] ^ bumped[1], lo0 };
31 }
32 return state;
33 }
34
35 pub fn philoxWords(
36 k: anytype,
37 rounds: u32,
38 counter: kernel.Value,
39 counter_fold: kernel.Value,
40 seed_lo: kernel.Value,
41 seed_hi: kernel.Value,
42 ) ![philox_lanes]kernel.Value {
43 const zero = try k.constantInt(.i32, 0);
44 const m0 = try wordConstant(k, philox_m0);
45 const m1 = try wordConstant(k, philox_m1);
46 const w0 = try wordConstant(k, philox_w0);
47 const w1 = try wordConstant(k, philox_w1);
48 var state = [philox_lanes]kernel.Value{ counter, counter_fold, zero, zero };
49 var key = [2]kernel.Value{ seed_lo, seed_hi };
50 var round: u32 = 0;
51 while (round < rounds) : (round += 1) {
52 if (round > 0) {
53 key[0] = try k.add(key[0], w0);
54 key[1] = try k.add(key[1], w1);
55 }
56 const hi0 = try k.umulhi(m0, state[0]);
57 const lo0 = try k.mul(m0, state[0]);
58 const hi1 = try k.umulhi(m1, state[2]);
59 const lo1 = try k.mul(m1, state[2]);
60 state = .{
61 try k.xor(try k.xor(hi1, state[1]), key[0]),
62 lo1,
63 try k.xor(try k.xor(hi0, state[3]), key[1]),
64 lo0,
65 };
66 }
67 return state;
68 }