| ... | @@ -34,7 +34,7 @@ const maxInt = std.math.maxInt; | ... | @@ -34,7 +34,7 @@ const maxInt = std.math.maxInt; |
| 34 | pub const DefaultPrng = Xoroshiro128; | 34 | pub const DefaultPrng = Xoroshiro128; |
| 35 | | 35 | |
| 36 | /// Cryptographically secure random numbers. | 36 | /// Cryptographically secure random numbers. |
| 37 | pub const DefaultCsprng = Isaac64; | 37 | pub const DefaultCsprng = Gimli; |
| 38 | | 38 | |
| 39 | pub const Random = struct { | 39 | pub const Random = struct { |
| 40 | fillFn: fn (r: *Random, buf: []u8) void, | 40 | fillFn: fn (r: *Random, buf: []u8) void, |
| ... | @@ -749,29 +749,35 @@ pub const Gimli = struct { | ... | @@ -749,29 +749,35 @@ pub const Gimli = struct { |
| 749 | random: Random, | 749 | random: Random, |
| 750 | state: std.crypto.core.Gimli, | 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 | var self = Gimli{ | 760 | var self = Gimli{ |
| 754 | .random = Random{ .fillFn = fill }, | 761 | .random = Random{ .fillFn = fill }, |
| 755 | .state = std.crypto.core.Gimli{ | 762 | .state = std.crypto.core.Gimli.init(initial_state), |
| 756 | .data = [_]u32{0} ** (std.crypto.gimli.State.BLOCKBYTES / 4), | | |
| 757 | }, | | |
| 758 | }; | 763 | }; |
| 759 | self.state.data[0] = @truncate(u32, init_s >> 32); | | |
| 760 | self.state.data[1] = @truncate(u32, init_s); | | |
| 761 | return self; | 764 | return self; |
| 762 | } | 765 | } |
| 763 | | 766 | |
| 764 | fn fill(r: *Random, buf: []u8) void { | 767 | fn fill(r: *Random, buf: []u8) void { |
| 765 | const self = @fieldParentPtr(Gimli, "random", r); | 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 | // ISAAC64 - http://www.burtleburtle.net/bob/rand/isaacafa.html | 779 | // ISAAC64 - http://www.burtleburtle.net/bob/rand/isaacafa.html |
| 772 | // | 780 | // |
| 773 | // CSPRNG | | |
| 774 | // | | |
| 775 | // Follows the general idea of the implementation from here with a few shortcuts. | 781 | // Follows the general idea of the implementation from here with a few shortcuts. |
| 776 | // https://doc.rust-lang.org/rand/src/rand/prng/isaac64.rs.html | 782 | // https://doc.rust-lang.org/rand/src/rand/prng/isaac64.rs.html |
| 777 | pub const Isaac64 = struct { | 783 | pub const Isaac64 = struct { |
| ... | @@ -1139,6 +1145,16 @@ fn testRangeBias(r: *Random, start: i8, end: i8, biased: bool) void { | ... | @@ -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 | test "" { | 1158 | test "" { |
| 1143 | std.testing.refAllDecls(@This()); | 1159 | std.testing.refAllDecls(@This()); |
| 1144 | } | 1160 | } |