| ... | ... | @@ -34,7 +34,7 @@ const maxInt = std.math.maxInt; |
| 34 | 34 | pub const DefaultPrng = Xoroshiro128; |
| 35 | 35 | |
| 36 | 36 | /// Cryptographically secure random numbers. |
| 37 | | pub const DefaultCsprng = Isaac64; |
| 37 | pub const DefaultCsprng = Gimli; |
| 38 | 38 | |
| 39 | 39 | pub const Random = struct { |
| 40 | 40 | fillFn: fn (r: *Random, buf: []u8) void, |
| ... | ... | @@ -749,29 +749,35 @@ pub const Gimli = struct { |
| 749 | 749 | random: Random, |
| 750 | 750 | state: std.crypto.core.Gimli, |
| 751 | 751 | |
| 752 | | pub fn init(init_s: u64) Gimli { |
| 752 | pub const secret_seed_length = 32; |
| 753 | |
| 754 | /// The seed must be uniform, secret and `secret_seed_length` bytes long. |
| 755 | /// It can be generated using `std.crypto.randomBytes()`. |
| 756 | pub fn init(secret_seed: [secret_seed_length]u8) Gimli { |
| 757 | var initial_state: [std.crypto.core.Gimli.BLOCKBYTES]u8 = undefined; |
| 758 | mem.copy(u8, initial_state[0..secret_seed_length], &secret_seed); |
| 759 | mem.set(u8, initial_state[secret_seed_length..], 0); |
| 753 | 760 | var self = Gimli{ |
| 754 | 761 | .random = Random{ .fillFn = fill }, |
| 755 | | .state = std.crypto.core.Gimli{ |
| 756 | | .data = [_]u32{0} ** (std.crypto.gimli.State.BLOCKBYTES / 4), |
| 757 | | }, |
| 762 | .state = std.crypto.core.Gimli.init(initial_state), |
| 758 | 763 | }; |
| 759 | | self.state.data[0] = @truncate(u32, init_s >> 32); |
| 760 | | self.state.data[1] = @truncate(u32, init_s); |
| 761 | 764 | return self; |
| 762 | 765 | } |
| 763 | 766 | |
| 764 | 767 | fn fill(r: *Random, buf: []u8) void { |
| 765 | 768 | const self = @fieldParentPtr(Gimli, "random", r); |
| 766 | 769 | |
| 767 | | self.state.squeeze(buf); |
| 770 | if (buf.len != 0) { |
| 771 | self.state.squeeze(buf); |
| 772 | } else { |
| 773 | self.state.permute(); |
| 774 | } |
| 775 | mem.set(u8, self.state.toSlice()[0..std.crypto.core.Gimli.RATE], 0); |
| 768 | 776 | } |
| 769 | 777 | }; |
| 770 | 778 | |
| 771 | 779 | // ISAAC64 - http://www.burtleburtle.net/bob/rand/isaacafa.html |
| 772 | 780 | // |
| 773 | | // CSPRNG |
| 774 | | // |
| 775 | 781 | // Follows the general idea of the implementation from here with a few shortcuts. |
| 776 | 782 | // https://doc.rust-lang.org/rand/src/rand/prng/isaac64.rs.html |
| 777 | 783 | pub const Isaac64 = struct { |
| ... | ... | @@ -1139,6 +1145,16 @@ fn testRangeBias(r: *Random, start: i8, end: i8, biased: bool) void { |
| 1139 | 1145 | } |
| 1140 | 1146 | } |
| 1141 | 1147 | |
| 1148 | test "CSPRNG" { |
| 1149 | var secret_seed: [DefaultCsprng.secret_seed_length]u8 = undefined; |
| 1150 | try std.crypto.randomBytes(&secret_seed); |
| 1151 | var csprng = DefaultCsprng.init(secret_seed); |
| 1152 | const a = csprng.random.int(u64); |
| 1153 | const b = csprng.random.int(u64); |
| 1154 | const c = csprng.random.int(u64); |
| 1155 | assert(a ^ b ^ c != 0); |
| 1156 | } |
| 1157 | |
| 1142 | 1158 | test "" { |
| 1143 | 1159 | std.testing.refAllDecls(@This()); |
| 1144 | 1160 | } |