| 1 | //! CSPRNG based on the Reverie construction, a permutation-based PRNG |
| 2 | //! with forward security, instantiated with the Ascon(128,12,8) permutation. |
| 3 | //! |
| 4 | //! Compared to ChaCha, this PRNG has a much smaller state, and can be |
| 5 | //! a better choice for constrained environments. |
| 6 | //! |
| 7 | //! References: |
| 8 | //! - A Robust and Sponge-Like PRNG with Improved Efficiency https://eprint.iacr.org/2016/886.pdf |
| 9 | //! - Ascon https://ascon.iaik.tugraz.at/files/asconv12-nist.pdf |
| 10 | |
| 11 | const std = @import("std"); |
| 12 | const mem = std.mem; |
| 13 | const Self = @This(); |
| 14 | |
| 15 | const Ascon = std.crypto.core.Ascon(.little); |
| 16 | |
| 17 | state: Ascon, |
| 18 | |
| 19 | const rate = 16; |
| 20 | pub const secret_seed_length = 32; |
| 21 | |
| 22 | /// The seed must be uniform, secret and `secret_seed_length` bytes long. |
| 23 | pub fn init(secret_seed: [secret_seed_length]u8) Self { |
| 24 | var self = Self{ .state = Ascon.initXof() }; |
| 25 | self.addEntropy(&secret_seed); |
| 26 | return self; |
| 27 | } |
| 28 | |
| 29 | /// Inserts entropy to refresh the internal state. |
| 30 | pub fn addEntropy(self: *Self, bytes: []const u8) void { |
| 31 | comptime std.debug.assert(secret_seed_length % rate == 0); |
| 32 | var i: usize = 0; |
| 33 | while (i + rate < bytes.len) : (i += rate) { |
| 34 | self.state.addBytes(bytes[i..][0..rate]); |
| 35 | self.state.permuteR(8); |
| 36 | } |
| 37 | if (i != bytes.len) self.state.addBytes(bytes[i..]); |
| 38 | self.state.permute(); |
| 39 | } |
| 40 | |
| 41 | /// Returns a `std.Random` structure backed by the current RNG. |
| 42 | pub fn random(self: *Self) std.Random { |
| 43 | return std.Random.init(self, fill); |
| 44 | } |
| 45 | |
| 46 | /// Fills the buffer with random bytes. |
| 47 | pub fn fill(self: *Self, buf: []u8) void { |
| 48 | var i: usize = 0; |
| 49 | while (true) { |
| 50 | const left = buf.len - i; |
| 51 | const n = @min(left, rate); |
| 52 | self.state.extractBytes(buf[i..][0..n]); |
| 53 | if (left == 0) break; |
| 54 | self.state.permuteR(8); |
| 55 | i += n; |
| 56 | } |
| 57 | self.state.permuteRatchet(6, rate); |
| 58 | } |