aboutsummaryrefslogtreecommitdiff
path: root/lib/std/Random/Ascon.zig
diff options
context:
space:
mode:
authore4m2 <git@e4m2.com>2024-02-08 14:43:20 +0100
committere4m2 <git@e4m2.com>2024-02-08 14:43:20 +0100
commit9af077d71eaf2c004d63405fc5c017e237cb9c6c (patch)
treee9a82339e59f49ae2b6fc57c893b3e16afaed9aa /lib/std/Random/Ascon.zig
parent919a3bae1c5f2024b09e127a15c752d9dc0aa9a6 (diff)
downloadzig-9af077d71eaf2c004d63405fc5c017e237cb9c6c.tar.gz
zig-9af077d71eaf2c004d63405fc5c017e237cb9c6c.zip
std.rand: Move to std.Random
Diffstat (limited to 'lib/std/Random/Ascon.zig')
-rw-r--r--lib/std/Random/Ascon.zig59
1 files changed, 59 insertions, 0 deletions
diff --git a/lib/std/Random/Ascon.zig b/lib/std/Random/Ascon.zig
new file mode 100644
index 0000000000..6a3cb13165
--- /dev/null
+++ b/lib/std/Random/Ascon.zig
@@ -0,0 +1,59 @@
+//! CSPRNG based on the Reverie construction, a permutation-based PRNG
+//! with forward security, instantiated with the Ascon(128,12,8) permutation.
+//!
+//! Compared to ChaCha, this PRNG has a much smaller state, and can be
+//! a better choice for constrained environments.
+//!
+//! References:
+//! - A Robust and Sponge-Like PRNG with Improved Efficiency https://eprint.iacr.org/2016/886.pdf
+//! - Ascon https://ascon.iaik.tugraz.at/files/asconv12-nist.pdf
+
+const std = @import("std");
+const mem = std.mem;
+const Random = std.rand.Random;
+const Self = @This();
+
+const Ascon = std.crypto.core.Ascon(.little);
+
+state: Ascon,
+
+const rate = 16;
+pub const secret_seed_length = 32;
+
+/// The seed must be uniform, secret and `secret_seed_length` bytes long.
+pub fn init(secret_seed: [secret_seed_length]u8) Self {
+ var self = Self{ .state = Ascon.initXof() };
+ self.addEntropy(&secret_seed);
+ return self;
+}
+
+/// Inserts entropy to refresh the internal state.
+pub fn addEntropy(self: *Self, bytes: []const u8) void {
+ comptime std.debug.assert(secret_seed_length % rate == 0);
+ var i: usize = 0;
+ while (i + rate < bytes.len) : (i += rate) {
+ self.state.addBytes(bytes[i..][0..rate]);
+ self.state.permuteR(8);
+ }
+ if (i != bytes.len) self.state.addBytes(bytes[i..]);
+ self.state.permute();
+}
+
+/// Returns a `std.rand.Random` structure backed by the current RNG.
+pub fn random(self: *Self) Random {
+ return Random.init(self, fill);
+}
+
+/// Fills the buffer with random bytes.
+pub fn fill(self: *Self, buf: []u8) void {
+ var i: usize = 0;
+ while (true) {
+ const left = buf.len - i;
+ const n = @min(left, rate);
+ self.state.extractBytes(buf[i..][0..n]);
+ if (left == 0) break;
+ self.state.permuteR(8);
+ i += n;
+ }
+ self.state.permuteRatchet(6, rate);
+}