Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std.rand: set DefaultCsprng to Gimli, and require a larger seed #6622

Merged
merged 1 commit into from
Oct 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions lib/std/crypto/gimli.zig
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ pub const State = struct {

const Self = @This();

pub fn init(initial_state: [State.BLOCKBYTES]u8) Self {
var data: [BLOCKBYTES / 4]u32 = undefined;
var i: usize = 0;
while (i < State.BLOCKBYTES) : (i += 4) {
data[i / 4] = mem.readIntLittle(u32, initial_state[i..][0..4]);
}
return Self{ .data = data };
}

/// TODO follow the span() convention instead of having this and `toSliceConst`
pub fn toSlice(self: *Self) []u8 {
return mem.sliceAsBytes(self.data[0..]);
Expand Down
36 changes: 26 additions & 10 deletions lib/std/rand.zig
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const maxInt = std.math.maxInt;
pub const DefaultPrng = Xoroshiro128;

/// Cryptographically secure random numbers.
pub const DefaultCsprng = Isaac64;
pub const DefaultCsprng = Gimli;

pub const Random = struct {
fillFn: fn (r: *Random, buf: []u8) void,
Expand Down Expand Up @@ -749,29 +749,35 @@ pub const Gimli = struct {
random: Random,
state: std.crypto.core.Gimli,

pub fn init(init_s: u64) Gimli {
pub const secret_seed_length = 32;
jedisct1 marked this conversation as resolved.
Show resolved Hide resolved
jedisct1 marked this conversation as resolved.
Show resolved Hide resolved

/// The seed must be uniform, secret and `secret_seed_length` bytes long.
/// It can be generated using `std.crypto.randomBytes()`.
pub fn init(secret_seed: [secret_seed_length]u8) Gimli {
jedisct1 marked this conversation as resolved.
Show resolved Hide resolved
var initial_state: [std.crypto.core.Gimli.BLOCKBYTES]u8 = undefined;
mem.copy(u8, initial_state[0..secret_seed_length], &secret_seed);
mem.set(u8, initial_state[secret_seed_length..], 0);
var self = Gimli{
.random = Random{ .fillFn = fill },
.state = std.crypto.core.Gimli{
.data = [_]u32{0} ** (std.crypto.gimli.State.BLOCKBYTES / 4),
},
.state = std.crypto.core.Gimli.init(initial_state),
};
self.state.data[0] = @truncate(u32, init_s >> 32);
self.state.data[1] = @truncate(u32, init_s);
return self;
}

fn fill(r: *Random, buf: []u8) void {
const self = @fieldParentPtr(Gimli, "random", r);

self.state.squeeze(buf);
if (buf.len != 0) {
self.state.squeeze(buf);
} else {
self.state.permute();
}
mem.set(u8, self.state.toSlice()[0..std.crypto.core.Gimli.RATE], 0);
jedisct1 marked this conversation as resolved.
Show resolved Hide resolved
}
};

// ISAAC64 - http://www.burtleburtle.net/bob/rand/isaacafa.html
//
// CSPRNG
//
// Follows the general idea of the implementation from here with a few shortcuts.
// https://doc.rust-lang.org/rand/src/rand/prng/isaac64.rs.html
pub const Isaac64 = struct {
Expand Down Expand Up @@ -1139,6 +1145,16 @@ fn testRangeBias(r: *Random, start: i8, end: i8, biased: bool) void {
}
}

test "CSPRNG" {
var secret_seed: [DefaultCsprng.secret_seed_length]u8 = undefined;
try std.crypto.randomBytes(&secret_seed);
var csprng = DefaultCsprng.init(secret_seed);
const a = csprng.random.int(u64);
const b = csprng.random.int(u64);
const c = csprng.random.int(u64);
assert(a ^ b ^ c != 0);
}

test "" {
std.meta.refAllDecls(@This());
}