authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-12-17 20:03:41-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-12-18 12:22:46-07:00
log013efaf13987acfa6b41d40f07900c1ea77f5bda
tree14325d114eb66312b3545f3a897142400dfb7c16
parentce65533985caa9e2da567948e36d7d4ba0185005

std: introduce a thread-local CSPRNG for general use

std.crypto.random * cross platform, even freestanding * can't fail. on initialization for some systems requires calling os.getrandom(), in which case there are rare but theoretically possible errors. The code panics in these cases, however the application may choose to override the default seed function and then handle the failure another way. * thread-safe * supports the full Random interface * cryptographically secure * no syscall required to initialize on Linux (AT_RANDOM) * calls arc4random on systems that support it `std.crypto.randomBytes` is removed in favor of `std.crypto.random.bytes`. I moved some of the Random implementations into their own files in the interest of organization. stage2 no longer requires passing a RNG; instead it uses this API. Closes #6704

24 files changed, 730 insertions(+), 629 deletions(-)

lib/std/crypto.zig+10-1
...@@ -134,8 +134,10 @@ pub const nacl = struct {...@@ -134,8 +134,10 @@ pub const nacl = struct {
134134
135pub const utils = @import("crypto/utils.zig");135pub const utils = @import("crypto/utils.zig");
136136
137/// This is a thread-local, cryptographically secure pseudo random number generator.
138pub const random = &@import("crypto/tlcsprng.zig").interface;
139
137const std = @import("std.zig");140const std = @import("std.zig");
138pub const randomBytes = std.os.getrandom;
139141
140test "crypto" {142test "crypto" {
141 inline for (std.meta.declarations(@This())) |decl| {143 inline for (std.meta.declarations(@This())) |decl| {
...@@ -178,6 +180,13 @@ test "crypto" {...@@ -178,6 +180,13 @@ test "crypto" {
178 _ = @import("crypto/25519/ristretto255.zig");180 _ = @import("crypto/25519/ristretto255.zig");
179}181}
180182
183test "CSPRNG" {
184 const a = random.int(u64);
185 const b = random.int(u64);
186 const c = random.int(u64);
187 std.testing.expect(a ^ b ^ c != 0);
188}
189
181test "issue #4532: no index out of bounds" {190test "issue #4532: no index out of bounds" {
182 const types = [_]type{191 const types = [_]type{
183 hash.Md5,192 hash.Md5,
lib/std/crypto/25519/ed25519.zig+4-4
...@@ -43,7 +43,7 @@ pub const Ed25519 = struct {...@@ -43,7 +43,7 @@ pub const Ed25519 = struct {
43 pub fn create(seed: ?[seed_length]u8) !KeyPair {43 pub fn create(seed: ?[seed_length]u8) !KeyPair {
44 const ss = seed orelse ss: {44 const ss = seed orelse ss: {
45 var random_seed: [seed_length]u8 = undefined;45 var random_seed: [seed_length]u8 = undefined;
46 try crypto.randomBytes(&random_seed);46 crypto.random.bytes(&random_seed);
47 break :ss random_seed;47 break :ss random_seed;
48 };48 };
49 var az: [Sha512.digest_length]u8 = undefined;49 var az: [Sha512.digest_length]u8 = undefined;
...@@ -179,7 +179,7 @@ pub const Ed25519 = struct {...@@ -179,7 +179,7 @@ pub const Ed25519 = struct {
179179
180 var z_batch: [count]Curve.scalar.CompressedScalar = undefined;180 var z_batch: [count]Curve.scalar.CompressedScalar = undefined;
181 for (z_batch) |*z| {181 for (z_batch) |*z| {
182 try std.crypto.randomBytes(z[0..16]);182 std.crypto.random.bytes(z[0..16]);
183 mem.set(u8, z[16..], 0);183 mem.set(u8, z[16..], 0);
184 }184 }
185185
...@@ -232,8 +232,8 @@ test "ed25519 batch verification" {...@@ -232,8 +232,8 @@ test "ed25519 batch verification" {
232 const key_pair = try Ed25519.KeyPair.create(null);232 const key_pair = try Ed25519.KeyPair.create(null);
233 var msg1: [32]u8 = undefined;233 var msg1: [32]u8 = undefined;
234 var msg2: [32]u8 = undefined;234 var msg2: [32]u8 = undefined;
235 try std.crypto.randomBytes(&msg1);235 std.crypto.random.bytes(&msg1);
236 try std.crypto.randomBytes(&msg2);236 std.crypto.random.bytes(&msg2);
237 const sig1 = try Ed25519.sign(&msg1, key_pair, null);237 const sig1 = try Ed25519.sign(&msg1, key_pair, null);
238 const sig2 = try Ed25519.sign(&msg2, key_pair, null);238 const sig2 = try Ed25519.sign(&msg2, key_pair, null);
239 var signature_batch = [_]Ed25519.BatchElement{239 var signature_batch = [_]Ed25519.BatchElement{
lib/std/crypto/25519/edwards25519.zig+2-2
...@@ -484,8 +484,8 @@ test "edwards25519 packing/unpacking" {...@@ -484,8 +484,8 @@ test "edwards25519 packing/unpacking" {
484test "edwards25519 point addition/substraction" {484test "edwards25519 point addition/substraction" {
485 var s1: [32]u8 = undefined;485 var s1: [32]u8 = undefined;
486 var s2: [32]u8 = undefined;486 var s2: [32]u8 = undefined;
487 try std.crypto.randomBytes(&s1);487 std.crypto.random.bytes(&s1);
488 try std.crypto.randomBytes(&s2);488 std.crypto.random.bytes(&s2);
489 const p = try Edwards25519.basePoint.clampedMul(s1);489 const p = try Edwards25519.basePoint.clampedMul(s1);
490 const q = try Edwards25519.basePoint.clampedMul(s2);490 const q = try Edwards25519.basePoint.clampedMul(s2);
491 const r = p.add(q).add(q).sub(q).sub(q);491 const r = p.add(q).add(q).sub(q).sub(q);
lib/std/crypto/25519/x25519.zig+1-1
...@@ -34,7 +34,7 @@ pub const X25519 = struct {...@@ -34,7 +34,7 @@ pub const X25519 = struct {
34 pub fn create(seed: ?[seed_length]u8) !KeyPair {34 pub fn create(seed: ?[seed_length]u8) !KeyPair {
35 const sk = seed orelse sk: {35 const sk = seed orelse sk: {
36 var random_seed: [seed_length]u8 = undefined;36 var random_seed: [seed_length]u8 = undefined;
37 try crypto.randomBytes(&random_seed);37 crypto.random.bytes(&random_seed);
38 break :sk random_seed;38 break :sk random_seed;
39 };39 };
40 var kp: KeyPair = undefined;40 var kp: KeyPair = undefined;
lib/std/crypto/bcrypt.zig+2-2
...@@ -262,7 +262,7 @@ fn strHashInternal(password: []const u8, rounds_log: u6, salt: [salt_length]u8)...@@ -262,7 +262,7 @@ fn strHashInternal(password: []const u8, rounds_log: u6, salt: [salt_length]u8)
262/// and then use the resulting hash as the password parameter for bcrypt.262/// and then use the resulting hash as the password parameter for bcrypt.
263pub fn strHash(password: []const u8, rounds_log: u6) ![hash_length]u8 {263pub fn strHash(password: []const u8, rounds_log: u6) ![hash_length]u8 {
264 var salt: [salt_length]u8 = undefined;264 var salt: [salt_length]u8 = undefined;
265 try crypto.randomBytes(&salt);265 crypto.random.bytes(&salt);
266 return strHashInternal(password, rounds_log, salt);266 return strHashInternal(password, rounds_log, salt);
267}267}
268268
...@@ -283,7 +283,7 @@ pub fn strVerify(h: [hash_length]u8, password: []const u8) BcryptError!void {...@@ -283,7 +283,7 @@ pub fn strVerify(h: [hash_length]u8, password: []const u8) BcryptError!void {
283283
284test "bcrypt codec" {284test "bcrypt codec" {
285 var salt: [salt_length]u8 = undefined;285 var salt: [salt_length]u8 = undefined;
286 try crypto.randomBytes(&salt);286 crypto.random.bytes(&salt);
287 var salt_str: [salt_str_length]u8 = undefined;287 var salt_str: [salt_str_length]u8 = undefined;
288 Codec.encode(salt_str[0..], salt[0..]);288 Codec.encode(salt_str[0..], salt[0..]);
289 var salt2: [salt_length]u8 = undefined;289 var salt2: [salt_length]u8 = undefined;
lib/std/crypto/salsa20.zig+9-9
...@@ -571,9 +571,9 @@ test "xsalsa20poly1305" {...@@ -571,9 +571,9 @@ test "xsalsa20poly1305" {
571 var key: [XSalsa20Poly1305.key_length]u8 = undefined;571 var key: [XSalsa20Poly1305.key_length]u8 = undefined;
572 var nonce: [XSalsa20Poly1305.nonce_length]u8 = undefined;572 var nonce: [XSalsa20Poly1305.nonce_length]u8 = undefined;
573 var tag: [XSalsa20Poly1305.tag_length]u8 = undefined;573 var tag: [XSalsa20Poly1305.tag_length]u8 = undefined;
574 try crypto.randomBytes(&msg);574 crypto.random.bytes(&msg);
575 try crypto.randomBytes(&key);575 crypto.random.bytes(&key);
576 try crypto.randomBytes(&nonce);576 crypto.random.bytes(&nonce);
577577
578 XSalsa20Poly1305.encrypt(c[0..], &tag, msg[0..], "ad", nonce, key);578 XSalsa20Poly1305.encrypt(c[0..], &tag, msg[0..], "ad", nonce, key);
579 try XSalsa20Poly1305.decrypt(msg2[0..], c[0..], tag, "ad", nonce, key);579 try XSalsa20Poly1305.decrypt(msg2[0..], c[0..], tag, "ad", nonce, key);
...@@ -585,9 +585,9 @@ test "xsalsa20poly1305 secretbox" {...@@ -585,9 +585,9 @@ test "xsalsa20poly1305 secretbox" {
585 var key: [XSalsa20Poly1305.key_length]u8 = undefined;585 var key: [XSalsa20Poly1305.key_length]u8 = undefined;
586 var nonce: [Box.nonce_length]u8 = undefined;586 var nonce: [Box.nonce_length]u8 = undefined;
587 var boxed: [msg.len + Box.tag_length]u8 = undefined;587 var boxed: [msg.len + Box.tag_length]u8 = undefined;
588 try crypto.randomBytes(&msg);588 crypto.random.bytes(&msg);
589 try crypto.randomBytes(&key);589 crypto.random.bytes(&key);
590 try crypto.randomBytes(&nonce);590 crypto.random.bytes(&nonce);
591591
592 SecretBox.seal(boxed[0..], msg[0..], nonce, key);592 SecretBox.seal(boxed[0..], msg[0..], nonce, key);
593 try SecretBox.open(msg2[0..], boxed[0..], nonce, key);593 try SecretBox.open(msg2[0..], boxed[0..], nonce, key);
...@@ -598,8 +598,8 @@ test "xsalsa20poly1305 box" {...@@ -598,8 +598,8 @@ test "xsalsa20poly1305 box" {
598 var msg2: [msg.len]u8 = undefined;598 var msg2: [msg.len]u8 = undefined;
599 var nonce: [Box.nonce_length]u8 = undefined;599 var nonce: [Box.nonce_length]u8 = undefined;
600 var boxed: [msg.len + Box.tag_length]u8 = undefined;600 var boxed: [msg.len + Box.tag_length]u8 = undefined;
601 try crypto.randomBytes(&msg);601 crypto.random.bytes(&msg);
602 try crypto.randomBytes(&nonce);602 crypto.random.bytes(&nonce);
603603
604 var kp1 = try Box.KeyPair.create(null);604 var kp1 = try Box.KeyPair.create(null);
605 var kp2 = try Box.KeyPair.create(null);605 var kp2 = try Box.KeyPair.create(null);
...@@ -611,7 +611,7 @@ test "xsalsa20poly1305 sealedbox" {...@@ -611,7 +611,7 @@ test "xsalsa20poly1305 sealedbox" {
611 var msg: [100]u8 = undefined;611 var msg: [100]u8 = undefined;
612 var msg2: [msg.len]u8 = undefined;612 var msg2: [msg.len]u8 = undefined;
613 var boxed: [msg.len + SealedBox.seal_length]u8 = undefined;613 var boxed: [msg.len + SealedBox.seal_length]u8 = undefined;
614 try crypto.randomBytes(&msg);614 crypto.random.bytes(&msg);
615615
616 var kp = try Box.KeyPair.create(null);616 var kp = try Box.KeyPair.create(null);
617 try SealedBox.seal(boxed[0..], msg[0..], kp.public_key);617 try SealedBox.seal(boxed[0..], msg[0..], kp.public_key);
lib/std/crypto/tlcsprng.zig created+62
...@@ -0,0 +1,62 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7//! Thread-local cryptographically secure pseudo-random number generator.
8//! This file has public declarations that are intended to be used internally
9//! by the standard library; this namespace is not intended to be exposed
10//! directly to standard library users.
11
12const std = @import("std");
13const root = @import("root");
14const mem = std.mem;
15
16/// We use this as a layer of indirection because global const pointers cannot
17/// point to thread-local variables.
18pub var interface = std.rand.Random{ .fillFn = tlsCsprngFill };
19pub threadlocal var csprng_state: std.crypto.core.Gimli = undefined;
20pub threadlocal var csprng_state_initialized = false;
21fn tlsCsprngFill(r: *std.rand.Random, buf: []u8) void {
22 if (std.builtin.link_libc and @hasDecl(std.c, "arc4random_buf")) {
23 // arc4random is already a thread-local CSPRNG.
24 return std.c.arc4random_buf(buf.ptr, buf.len);
25 }
26 if (!csprng_state_initialized) {
27 var seed: [seed_len]u8 = undefined;
28 // Because we panic on getrandom() failing, we provide the opportunity
29 // to override the default seed function. This also makes
30 // `std.crypto.random` available on freestanding targets, provided that
31 // the `cryptoRandomSeed` function is provided.
32 if (@hasDecl(root, "cryptoRandomSeed")) {
33 root.cryptoRandomSeed(&seed);
34 } else {
35 defaultSeed(&seed);
36 }
37 init(seed);
38 }
39 if (buf.len != 0) {
40 csprng_state.squeeze(buf);
41 } else {
42 csprng_state.permute();
43 }
44 mem.set(u8, csprng_state.toSlice()[0..std.crypto.core.Gimli.RATE], 0);
45}
46
47fn defaultSeed(buffer: *[seed_len]u8) void {
48 std.os.getrandom(buffer) catch @panic("getrandom() failed to seed thread-local CSPRNG");
49}
50
51pub const seed_len = 32;
52
53pub fn init(seed: [seed_len]u8) void {
54 var initial_state: [std.crypto.core.Gimli.BLOCKBYTES]u8 = undefined;
55 mem.copy(u8, initial_state[0..seed_len], &seed);
56 mem.set(u8, initial_state[seed_len..], 0);
57 csprng_state = std.crypto.core.Gimli.init(initial_state);
58
59 // This is at the end so that accidental recursive dependencies result
60 // in stack overflows instead of invalid random data.
61 csprng_state_initialized = true;
62}
lib/std/crypto/utils.zig+4-4
...@@ -51,8 +51,8 @@ pub fn secureZero(comptime T: type, s: []T) void {...@@ -51,8 +51,8 @@ pub fn secureZero(comptime T: type, s: []T) void {
51test "crypto.utils.timingSafeEql" {51test "crypto.utils.timingSafeEql" {
52 var a: [100]u8 = undefined;52 var a: [100]u8 = undefined;
53 var b: [100]u8 = undefined;53 var b: [100]u8 = undefined;
54 try std.crypto.randomBytes(a[0..]);54 std.crypto.random.bytes(a[0..]);
55 try std.crypto.randomBytes(b[0..]);55 std.crypto.random.bytes(b[0..]);
56 testing.expect(!timingSafeEql([100]u8, a, b));56 testing.expect(!timingSafeEql([100]u8, a, b));
57 mem.copy(u8, a[0..], b[0..]);57 mem.copy(u8, a[0..], b[0..]);
58 testing.expect(timingSafeEql([100]u8, a, b));58 testing.expect(timingSafeEql([100]u8, a, b));
...@@ -61,8 +61,8 @@ test "crypto.utils.timingSafeEql" {...@@ -61,8 +61,8 @@ test "crypto.utils.timingSafeEql" {
61test "crypto.utils.timingSafeEql (vectors)" {61test "crypto.utils.timingSafeEql (vectors)" {
62 var a: [100]u8 = undefined;62 var a: [100]u8 = undefined;
63 var b: [100]u8 = undefined;63 var b: [100]u8 = undefined;
64 try std.crypto.randomBytes(a[0..]);64 std.crypto.random.bytes(a[0..]);
65 try std.crypto.randomBytes(b[0..]);65 std.crypto.random.bytes(b[0..]);
66 const v1: std.meta.Vector(100, u8) = a;66 const v1: std.meta.Vector(100, u8) = a;
67 const v2: std.meta.Vector(100, u8) = b;67 const v2: std.meta.Vector(100, u8) = b;
68 testing.expect(!timingSafeEql(std.meta.Vector(100, u8), v1, v2));68 testing.expect(!timingSafeEql(std.meta.Vector(100, u8), v1, v2));
lib/std/fs.zig+2-2
...@@ -82,7 +82,7 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path:...@@ -82,7 +82,7 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path:
82 mem.copy(u8, tmp_path[0..], dirname);82 mem.copy(u8, tmp_path[0..], dirname);
83 tmp_path[dirname.len] = path.sep;83 tmp_path[dirname.len] = path.sep;
84 while (true) {84 while (true) {
85 try crypto.randomBytes(rand_buf[0..]);85 crypto.random.bytes(rand_buf[0..]);
86 base64_encoder.encode(tmp_path[dirname.len + 1 ..], &rand_buf);86 base64_encoder.encode(tmp_path[dirname.len + 1 ..], &rand_buf);
8787
88 if (cwd().symLink(existing_path, tmp_path, .{})) {88 if (cwd().symLink(existing_path, tmp_path, .{})) {
...@@ -157,7 +157,7 @@ pub const AtomicFile = struct {...@@ -157,7 +157,7 @@ pub const AtomicFile = struct {
157 tmp_path_buf[base64.Base64Encoder.calcSize(RANDOM_BYTES)] = 0;157 tmp_path_buf[base64.Base64Encoder.calcSize(RANDOM_BYTES)] = 0;
158158
159 while (true) {159 while (true) {
160 try crypto.randomBytes(rand_buf[0..]);160 crypto.random.bytes(rand_buf[0..]);
161 base64_encoder.encode(&tmp_path_buf, &rand_buf);161 base64_encoder.encode(&tmp_path_buf, &rand_buf);
162162
163 const file = dir.createFile(163 const file = dir.createFile(
lib/std/rand.zig+13-566
...@@ -4,19 +4,11 @@...@@ -4,19 +4,11 @@
4// The MIT license requires this copyright notice to be included in all copies4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.5// and substantial portions of the software.
66
7//! The engines provided here should be initialized from an external source. For now, randomBytes7//! The engines provided here should be initialized from an external source.
8//! from the crypto package is the most suitable. Be sure to use a CSPRNG when required, otherwise using8//! For a thread-local cryptographically secure pseudo random number generator,
9//! a normal PRNG will be faster and use substantially less stack space.9//! use `std.crypto.random`.
10//!10//! Be sure to use a CSPRNG when required, otherwise using a normal PRNG will
11//! ```11//! be faster and use substantially less stack space.
12//! var buf: [8]u8 = undefined;
13//! try std.crypto.randomBytes(buf[0..]);
14//! const seed = mem.readIntLittle(u64, buf[0..8]);
15//!
16//! var r = DefaultPrng.init(seed);
17//!
18//! const s = r.random.int(u64);
19//! ```
20//!12//!
21//! TODO(tiehuis): Benchmark these against other reference implementations.13//! TODO(tiehuis): Benchmark these against other reference implementations.
2214
...@@ -36,6 +28,12 @@ pub const DefaultPrng = Xoroshiro128;...@@ -36,6 +28,12 @@ pub const DefaultPrng = Xoroshiro128;
36/// Cryptographically secure random numbers.28/// Cryptographically secure random numbers.
37pub const DefaultCsprng = Gimli;29pub const DefaultCsprng = Gimli;
3830
31pub const Isaac64 = @import("rand/Isaac64.zig");
32pub const Gimli = @import("rand/Gimli.zig");
33pub const Pcg = @import("rand/Pcg.zig");
34pub const Xoroshiro128 = @import("rand/Xoroshiro128.zig");
35pub const Sfc64 = @import("rand/Sfc64.zig");
36
39pub const Random = struct {37pub const Random = struct {
40 fillFn: fn (r: *Random, buf: []u8) void,38 fillFn: fn (r: *Random, buf: []u8) void,
4139
...@@ -491,7 +489,7 @@ test "Random Biased" {...@@ -491,7 +489,7 @@ test "Random Biased" {
491//489//
492// The number of cycles is thus limited to 64-bits regardless of the engine, but this490// The number of cycles is thus limited to 64-bits regardless of the engine, but this
493// is still plenty for practical purposes.491// is still plenty for practical purposes.
494const SplitMix64 = struct {492pub const SplitMix64 = struct {
495 s: u64,493 s: u64,
496494
497 pub fn init(seed: u64) SplitMix64 {495 pub fn init(seed: u64) SplitMix64 {
...@@ -525,557 +523,6 @@ test "splitmix64 sequence" {...@@ -525,557 +523,6 @@ test "splitmix64 sequence" {
525 }523 }
526}524}
527525
528// PCG32 - http://www.pcg-random.org/
529//
530// PRNG
531pub const Pcg = struct {
532 const default_multiplier = 6364136223846793005;
533
534 random: Random,
535
536 s: u64,
537 i: u64,
538
539 pub fn init(init_s: u64) Pcg {
540 var pcg = Pcg{
541 .random = Random{ .fillFn = fill },
542 .s = undefined,
543 .i = undefined,
544 };
545
546 pcg.seed(init_s);
547 return pcg;
548 }
549
550 fn next(self: *Pcg) u32 {
551 const l = self.s;
552 self.s = l *% default_multiplier +% (self.i | 1);
553
554 const xor_s = @truncate(u32, ((l >> 18) ^ l) >> 27);
555 const rot = @intCast(u32, l >> 59);
556
557 return (xor_s >> @intCast(u5, rot)) | (xor_s << @intCast(u5, (0 -% rot) & 31));
558 }
559
560 fn seed(self: *Pcg, init_s: u64) void {
561 // Pcg requires 128-bits of seed.
562 var gen = SplitMix64.init(init_s);
563 self.seedTwo(gen.next(), gen.next());
564 }
565
566 fn seedTwo(self: *Pcg, init_s: u64, init_i: u64) void {
567 self.s = 0;
568 self.i = (init_s << 1) | 1;
569 self.s = self.s *% default_multiplier +% self.i;
570 self.s +%= init_i;
571 self.s = self.s *% default_multiplier +% self.i;
572 }
573
574 fn fill(r: *Random, buf: []u8) void {
575 const self = @fieldParentPtr(Pcg, "random", r);
576
577 var i: usize = 0;
578 const aligned_len = buf.len - (buf.len & 7);
579
580 // Complete 4 byte segments.
581 while (i < aligned_len) : (i += 4) {
582 var n = self.next();
583 comptime var j: usize = 0;
584 inline while (j < 4) : (j += 1) {
585 buf[i + j] = @truncate(u8, n);
586 n >>= 8;
587 }
588 }
589
590 // Remaining. (cuts the stream)
591 if (i != buf.len) {
592 var n = self.next();
593 while (i < buf.len) : (i += 1) {
594 buf[i] = @truncate(u8, n);
595 n >>= 4;
596 }
597 }
598 }
599};
600
601test "pcg sequence" {
602 var r = Pcg.init(0);
603 const s0: u64 = 0x9394bf54ce5d79de;
604 const s1: u64 = 0x84e9c579ef59bbf7;
605 r.seedTwo(s0, s1);
606
607 const seq = [_]u32{
608 2881561918,
609 3063928540,
610 1199791034,
611 2487695858,
612 1479648952,
613 3247963454,
614 };
615
616 for (seq) |s| {
617 expect(s == r.next());
618 }
619}
620
621// Xoroshiro128+ - http://xoroshiro.di.unimi.it/
622//
623// PRNG
624pub const Xoroshiro128 = struct {
625 random: Random,
626
627 s: [2]u64,
628
629 pub fn init(init_s: u64) Xoroshiro128 {
630 var x = Xoroshiro128{
631 .random = Random{ .fillFn = fill },
632 .s = undefined,
633 };
634
635 x.seed(init_s);
636 return x;
637 }
638
639 fn next(self: *Xoroshiro128) u64 {
640 const s0 = self.s[0];
641 var s1 = self.s[1];
642 const r = s0 +% s1;
643
644 s1 ^= s0;
645 self.s[0] = math.rotl(u64, s0, @as(u8, 55)) ^ s1 ^ (s1 << 14);
646 self.s[1] = math.rotl(u64, s1, @as(u8, 36));
647
648 return r;
649 }
650
651 // Skip 2^64 places ahead in the sequence
652 fn jump(self: *Xoroshiro128) void {
653 var s0: u64 = 0;
654 var s1: u64 = 0;
655
656 const table = [_]u64{
657 0xbeac0467eba5facb,
658 0xd86b048b86aa9922,
659 };
660
661 inline for (table) |entry| {
662 var b: usize = 0;
663 while (b < 64) : (b += 1) {
664 if ((entry & (@as(u64, 1) << @intCast(u6, b))) != 0) {
665 s0 ^= self.s[0];
666 s1 ^= self.s[1];
667 }
668 _ = self.next();
669 }
670 }
671
672 self.s[0] = s0;
673 self.s[1] = s1;
674 }
675
676 pub fn seed(self: *Xoroshiro128, init_s: u64) void {
677 // Xoroshiro requires 128-bits of seed.
678 var gen = SplitMix64.init(init_s);
679
680 self.s[0] = gen.next();
681 self.s[1] = gen.next();
682 }
683
684 fn fill(r: *Random, buf: []u8) void {
685 const self = @fieldParentPtr(Xoroshiro128, "random", r);
686
687 var i: usize = 0;
688 const aligned_len = buf.len - (buf.len & 7);
689
690 // Complete 8 byte segments.
691 while (i < aligned_len) : (i += 8) {
692 var n = self.next();
693 comptime var j: usize = 0;
694 inline while (j < 8) : (j += 1) {
695 buf[i + j] = @truncate(u8, n);
696 n >>= 8;
697 }
698 }
699
700 // Remaining. (cuts the stream)
701 if (i != buf.len) {
702 var n = self.next();
703 while (i < buf.len) : (i += 1) {
704 buf[i] = @truncate(u8, n);
705 n >>= 8;
706 }
707 }
708 }
709};
710
711test "xoroshiro sequence" {
712 var r = Xoroshiro128.init(0);
713 r.s[0] = 0xaeecf86f7878dd75;
714 r.s[1] = 0x01cd153642e72622;
715
716 const seq1 = [_]u64{
717 0xb0ba0da5bb600397,
718 0x18a08afde614dccc,
719 0xa2635b956a31b929,
720 0xabe633c971efa045,
721 0x9ac19f9706ca3cac,
722 0xf62b426578c1e3fb,
723 };
724
725 for (seq1) |s| {
726 expect(s == r.next());
727 }
728
729 r.jump();
730
731 const seq2 = [_]u64{
732 0x95344a13556d3e22,
733 0xb4fb32dafa4d00df,
734 0xb2011d9ccdcfe2dd,
735 0x05679a9b2119b908,
736 0xa860a1da7c9cd8a0,
737 0x658a96efe3f86550,
738 };
739
740 for (seq2) |s| {
741 expect(s == r.next());
742 }
743}
744
745// Gimli
746//
747// CSPRNG
748pub const Gimli = struct {
749 random: Random,
750 state: std.crypto.core.Gimli,
751
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);
760 var self = Gimli{
761 .random = Random{ .fillFn = fill },
762 .state = std.crypto.core.Gimli.init(initial_state),
763 };
764 return self;
765 }
766
767 fn fill(r: *Random, buf: []u8) void {
768 const self = @fieldParentPtr(Gimli, "random", r);
769
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);
776 }
777};
778
779// ISAAC64 - http://www.burtleburtle.net/bob/rand/isaacafa.html
780//
781// Follows the general idea of the implementation from here with a few shortcuts.
782// https://doc.rust-lang.org/rand/src/rand/prng/isaac64.rs.html
783pub const Isaac64 = struct {
784 random: Random,
785
786 r: [256]u64,
787 m: [256]u64,
788 a: u64,
789 b: u64,
790 c: u64,
791 i: usize,
792
793 pub fn init(init_s: u64) Isaac64 {
794 var isaac = Isaac64{
795 .random = Random{ .fillFn = fill },
796 .r = undefined,
797 .m = undefined,
798 .a = undefined,
799 .b = undefined,
800 .c = undefined,
801 .i = undefined,
802 };
803
804 // seed == 0 => same result as the unseeded reference implementation
805 isaac.seed(init_s, 1);
806 return isaac;
807 }
808
809 fn step(self: *Isaac64, mix: u64, base: usize, comptime m1: usize, comptime m2: usize) void {
810 const x = self.m[base + m1];
811 self.a = mix +% self.m[base + m2];
812
813 const y = self.a +% self.b +% self.m[@intCast(usize, (x >> 3) % self.m.len)];
814 self.m[base + m1] = y;
815
816 self.b = x +% self.m[@intCast(usize, (y >> 11) % self.m.len)];
817 self.r[self.r.len - 1 - base - m1] = self.b;
818 }
819
820 fn refill(self: *Isaac64) void {
821 const midpoint = self.r.len / 2;
822
823 self.c +%= 1;
824 self.b +%= self.c;
825
826 {
827 var i: usize = 0;
828 while (i < midpoint) : (i += 4) {
829 self.step(~(self.a ^ (self.a << 21)), i + 0, 0, midpoint);
830 self.step(self.a ^ (self.a >> 5), i + 1, 0, midpoint);
831 self.step(self.a ^ (self.a << 12), i + 2, 0, midpoint);
832 self.step(self.a ^ (self.a >> 33), i + 3, 0, midpoint);
833 }
834 }
835
836 {
837 var i: usize = 0;
838 while (i < midpoint) : (i += 4) {
839 self.step(~(self.a ^ (self.a << 21)), i + 0, midpoint, 0);
840 self.step(self.a ^ (self.a >> 5), i + 1, midpoint, 0);
841 self.step(self.a ^ (self.a << 12), i + 2, midpoint, 0);
842 self.step(self.a ^ (self.a >> 33), i + 3, midpoint, 0);
843 }
844 }
845
846 self.i = 0;
847 }
848
849 fn next(self: *Isaac64) u64 {
850 if (self.i >= self.r.len) {
851 self.refill();
852 }
853
854 const value = self.r[self.i];
855 self.i += 1;
856 return value;
857 }
858
859 fn seed(self: *Isaac64, init_s: u64, comptime rounds: usize) void {
860 // We ignore the multi-pass requirement since we don't currently expose full access to
861 // seeding the self.m array completely.
862 mem.set(u64, self.m[0..], 0);
863 self.m[0] = init_s;
864
865 // prescrambled golden ratio constants
866 var a = [_]u64{
867 0x647c4677a2884b7c,
868 0xb9f8b322c73ac862,
869 0x8c0ea5053d4712a0,
870 0xb29b2e824a595524,
871 0x82f053db8355e0ce,
872 0x48fe4a0fa5a09315,
873 0xae985bf2cbfc89ed,
874 0x98f5704f6c44c0ab,
875 };
876
877 comptime var i: usize = 0;
878 inline while (i < rounds) : (i += 1) {
879 var j: usize = 0;
880 while (j < self.m.len) : (j += 8) {
881 comptime var x1: usize = 0;
882 inline while (x1 < 8) : (x1 += 1) {
883 a[x1] +%= self.m[j + x1];
884 }
885
886 a[0] -%= a[4];
887 a[5] ^= a[7] >> 9;
888 a[7] +%= a[0];
889 a[1] -%= a[5];
890 a[6] ^= a[0] << 9;
891 a[0] +%= a[1];
892 a[2] -%= a[6];
893 a[7] ^= a[1] >> 23;
894 a[1] +%= a[2];
895 a[3] -%= a[7];
896 a[0] ^= a[2] << 15;
897 a[2] +%= a[3];
898 a[4] -%= a[0];
899 a[1] ^= a[3] >> 14;
900 a[3] +%= a[4];
901 a[5] -%= a[1];
902 a[2] ^= a[4] << 20;
903 a[4] +%= a[5];
904 a[6] -%= a[2];
905 a[3] ^= a[5] >> 17;
906 a[5] +%= a[6];
907 a[7] -%= a[3];
908 a[4] ^= a[6] << 14;
909 a[6] +%= a[7];
910
911 comptime var x2: usize = 0;
912 inline while (x2 < 8) : (x2 += 1) {
913 self.m[j + x2] = a[x2];
914 }
915 }
916 }
917
918 mem.set(u64, self.r[0..], 0);
919 self.a = 0;
920 self.b = 0;
921 self.c = 0;
922 self.i = self.r.len; // trigger refill on first value
923 }
924
925 fn fill(r: *Random, buf: []u8) void {
926 const self = @fieldParentPtr(Isaac64, "random", r);
927
928 var i: usize = 0;
929 const aligned_len = buf.len - (buf.len & 7);
930
931 // Fill complete 64-byte segments
932 while (i < aligned_len) : (i += 8) {
933 var n = self.next();
934 comptime var j: usize = 0;
935 inline while (j < 8) : (j += 1) {
936 buf[i + j] = @truncate(u8, n);
937 n >>= 8;
938 }
939 }
940
941 // Fill trailing, ignoring excess (cut the stream).
942 if (i != buf.len) {
943 var n = self.next();
944 while (i < buf.len) : (i += 1) {
945 buf[i] = @truncate(u8, n);
946 n >>= 8;
947 }
948 }
949 }
950};
951
952test "isaac64 sequence" {
953 var r = Isaac64.init(0);
954
955 // from reference implementation
956 const seq = [_]u64{
957 0xf67dfba498e4937c,
958 0x84a5066a9204f380,
959 0xfee34bd5f5514dbb,
960 0x4d1664739b8f80d6,
961 0x8607459ab52a14aa,
962 0x0e78bc5a98529e49,
963 0xfe5332822ad13777,
964 0x556c27525e33d01a,
965 0x08643ca615f3149f,
966 0xd0771faf3cb04714,
967 0x30e86f68a37b008d,
968 0x3074ebc0488a3adf,
969 0x270645ea7a2790bc,
970 0x5601a0a8d3763c6a,
971 0x2f83071f53f325dd,
972 0xb9090f3d42d2d2ea,
973 };
974
975 for (seq) |s| {
976 expect(s == r.next());
977 }
978}
979
980/// Sfc64 pseudo-random number generator from Practically Random.
981/// Fastest engine of pracrand and smallest footprint.
982/// See http://pracrand.sourceforge.net/
983pub const Sfc64 = struct {
984 random: Random,
985
986 a: u64 = undefined,
987 b: u64 = undefined,
988 c: u64 = undefined,
989 counter: u64 = undefined,
990
991 const Rotation = 24;
992 const RightShift = 11;
993 const LeftShift = 3;
994
995 pub fn init(init_s: u64) Sfc64 {
996 var x = Sfc64{
997 .random = Random{ .fillFn = fill },
998 };
999
1000 x.seed(init_s);
1001 return x;
1002 }
1003
1004 fn next(self: *Sfc64) u64 {
1005 const tmp = self.a +% self.b +% self.counter;
1006 self.counter += 1;
1007 self.a = self.b ^ (self.b >> RightShift);
1008 self.b = self.c +% (self.c << LeftShift);
1009 self.c = math.rotl(u64, self.c, Rotation) +% tmp;
1010 return tmp;
1011 }
1012
1013 fn seed(self: *Sfc64, init_s: u64) void {
1014 self.a = init_s;
1015 self.b = init_s;
1016 self.c = init_s;
1017 self.counter = 1;
1018 var i: u32 = 0;
1019 while (i < 12) : (i += 1) {
1020 _ = self.next();
1021 }
1022 }
1023
1024 fn fill(r: *Random, buf: []u8) void {
1025 const self = @fieldParentPtr(Sfc64, "random", r);
1026
1027 var i: usize = 0;
1028 const aligned_len = buf.len - (buf.len & 7);
1029
1030 // Complete 8 byte segments.
1031 while (i < aligned_len) : (i += 8) {
1032 var n = self.next();
1033 comptime var j: usize = 0;
1034 inline while (j < 8) : (j += 1) {
1035 buf[i + j] = @truncate(u8, n);
1036 n >>= 8;
1037 }
1038 }
1039
1040 // Remaining. (cuts the stream)
1041 if (i != buf.len) {
1042 var n = self.next();
1043 while (i < buf.len) : (i += 1) {
1044 buf[i] = @truncate(u8, n);
1045 n >>= 8;
1046 }
1047 }
1048 }
1049};
1050
1051test "Sfc64 sequence" {
1052 // Unfortunately there does not seem to be an official test sequence.
1053 var r = Sfc64.init(0);
1054
1055 const seq = [_]u64{
1056 0x3acfa029e3cc6041,
1057 0xf5b6515bf2ee419c,
1058 0x1259635894a29b61,
1059 0xb6ae75395f8ebd6,
1060 0x225622285ce302e2,
1061 0x520d28611395cb21,
1062 0xdb909c818901599d,
1063 0x8ffd195365216f57,
1064 0xe8c4ad5e258ac04a,
1065 0x8f8ef2c89fdb63ca,
1066 0xf9865b01d98d8e2f,
1067 0x46555871a65d08ba,
1068 0x66868677c6298fcd,
1069 0x2ce15a7e6329f57d,
1070 0xb2f1833ca91ca79,
1071 0x4b0890ac9bf453ca,
1072 };
1073
1074 for (seq) |s| {
1075 expectEqual(s, r.next());
1076 }
1077}
1078
1079// Actual Random helper function tests, pcg engine is assumed correct.526// Actual Random helper function tests, pcg engine is assumed correct.
1080test "Random float" {527test "Random float" {
1081 var prng = DefaultPrng.init(0);528 var prng = DefaultPrng.init(0);
...@@ -1147,7 +594,7 @@ fn testRangeBias(r: *Random, start: i8, end: i8, biased: bool) void {...@@ -1147,7 +594,7 @@ fn testRangeBias(r: *Random, start: i8, end: i8, biased: bool) void {
1147594
1148test "CSPRNG" {595test "CSPRNG" {
1149 var secret_seed: [DefaultCsprng.secret_seed_length]u8 = undefined;596 var secret_seed: [DefaultCsprng.secret_seed_length]u8 = undefined;
1150 try std.crypto.randomBytes(&secret_seed);597 std.crypto.random.bytes(&secret_seed);
1151 var csprng = DefaultCsprng.init(secret_seed);598 var csprng = DefaultCsprng.init(secret_seed);
1152 const a = csprng.random.int(u64);599 const a = csprng.random.int(u64);
1153 const b = csprng.random.int(u64);600 const b = csprng.random.int(u64);
lib/std/rand/Gimli.zig created+40
...@@ -0,0 +1,40 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7//! CSPRNG
8
9const std = @import("std");
10const Random = std.rand.Random;
11const mem = std.mem;
12const Gimli = @This();
13
14random: Random,
15state: std.crypto.core.Gimli,
16
17pub const secret_seed_length = 32;
18
19/// The seed must be uniform, secret and `secret_seed_length` bytes long.
20pub fn init(secret_seed: [secret_seed_length]u8) Gimli {
21 var initial_state: [std.crypto.core.Gimli.BLOCKBYTES]u8 = undefined;
22 mem.copy(u8, initial_state[0..secret_seed_length], &secret_seed);
23 mem.set(u8, initial_state[secret_seed_length..], 0);
24 var self = Gimli{
25 .random = Random{ .fillFn = fill },
26 .state = std.crypto.core.Gimli.init(initial_state),
27 };
28 return self;
29}
30
31fn fill(r: *Random, buf: []u8) void {
32 const self = @fieldParentPtr(Gimli, "random", r);
33
34 if (buf.len != 0) {
35 self.state.squeeze(buf);
36 } else {
37 self.state.permute();
38 }
39 mem.set(u8, self.state.toSlice()[0..std.crypto.core.Gimli.RATE], 0);
40}
lib/std/rand/Isaac64.zig created+210
...@@ -0,0 +1,210 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7//! ISAAC64 - http://www.burtleburtle.net/bob/rand/isaacafa.html
8//!
9//! Follows the general idea of the implementation from here with a few shortcuts.
10//! https://doc.rust-lang.org/rand/src/rand/prng/isaac64.rs.html
11
12const std = @import("std");
13const Random = std.rand.Random;
14const mem = std.mem;
15const Isaac64 = @This();
16
17random: Random,
18
19r: [256]u64,
20m: [256]u64,
21a: u64,
22b: u64,
23c: u64,
24i: usize,
25
26pub fn init(init_s: u64) Isaac64 {
27 var isaac = Isaac64{
28 .random = Random{ .fillFn = fill },
29 .r = undefined,
30 .m = undefined,
31 .a = undefined,
32 .b = undefined,
33 .c = undefined,
34 .i = undefined,
35 };
36
37 // seed == 0 => same result as the unseeded reference implementation
38 isaac.seed(init_s, 1);
39 return isaac;
40}
41
42fn step(self: *Isaac64, mix: u64, base: usize, comptime m1: usize, comptime m2: usize) void {
43 const x = self.m[base + m1];
44 self.a = mix +% self.m[base + m2];
45
46 const y = self.a +% self.b +% self.m[@intCast(usize, (x >> 3) % self.m.len)];
47 self.m[base + m1] = y;
48
49 self.b = x +% self.m[@intCast(usize, (y >> 11) % self.m.len)];
50 self.r[self.r.len - 1 - base - m1] = self.b;
51}
52
53fn refill(self: *Isaac64) void {
54 const midpoint = self.r.len / 2;
55
56 self.c +%= 1;
57 self.b +%= self.c;
58
59 {
60 var i: usize = 0;
61 while (i < midpoint) : (i += 4) {
62 self.step(~(self.a ^ (self.a << 21)), i + 0, 0, midpoint);
63 self.step(self.a ^ (self.a >> 5), i + 1, 0, midpoint);
64 self.step(self.a ^ (self.a << 12), i + 2, 0, midpoint);
65 self.step(self.a ^ (self.a >> 33), i + 3, 0, midpoint);
66 }
67 }
68
69 {
70 var i: usize = 0;
71 while (i < midpoint) : (i += 4) {
72 self.step(~(self.a ^ (self.a << 21)), i + 0, midpoint, 0);
73 self.step(self.a ^ (self.a >> 5), i + 1, midpoint, 0);
74 self.step(self.a ^ (self.a << 12), i + 2, midpoint, 0);
75 self.step(self.a ^ (self.a >> 33), i + 3, midpoint, 0);
76 }
77 }
78
79 self.i = 0;
80}
81
82fn next(self: *Isaac64) u64 {
83 if (self.i >= self.r.len) {
84 self.refill();
85 }
86
87 const value = self.r[self.i];
88 self.i += 1;
89 return value;
90}
91
92fn seed(self: *Isaac64, init_s: u64, comptime rounds: usize) void {
93 // We ignore the multi-pass requirement since we don't currently expose full access to
94 // seeding the self.m array completely.
95 mem.set(u64, self.m[0..], 0);
96 self.m[0] = init_s;
97
98 // prescrambled golden ratio constants
99 var a = [_]u64{
100 0x647c4677a2884b7c,
101 0xb9f8b322c73ac862,
102 0x8c0ea5053d4712a0,
103 0xb29b2e824a595524,
104 0x82f053db8355e0ce,
105 0x48fe4a0fa5a09315,
106 0xae985bf2cbfc89ed,
107 0x98f5704f6c44c0ab,
108 };
109
110 comptime var i: usize = 0;
111 inline while (i < rounds) : (i += 1) {
112 var j: usize = 0;
113 while (j < self.m.len) : (j += 8) {
114 comptime var x1: usize = 0;
115 inline while (x1 < 8) : (x1 += 1) {
116 a[x1] +%= self.m[j + x1];
117 }
118
119 a[0] -%= a[4];
120 a[5] ^= a[7] >> 9;
121 a[7] +%= a[0];
122 a[1] -%= a[5];
123 a[6] ^= a[0] << 9;
124 a[0] +%= a[1];
125 a[2] -%= a[6];
126 a[7] ^= a[1] >> 23;
127 a[1] +%= a[2];
128 a[3] -%= a[7];
129 a[0] ^= a[2] << 15;
130 a[2] +%= a[3];
131 a[4] -%= a[0];
132 a[1] ^= a[3] >> 14;
133 a[3] +%= a[4];
134 a[5] -%= a[1];
135 a[2] ^= a[4] << 20;
136 a[4] +%= a[5];
137 a[6] -%= a[2];
138 a[3] ^= a[5] >> 17;
139 a[5] +%= a[6];
140 a[7] -%= a[3];
141 a[4] ^= a[6] << 14;
142 a[6] +%= a[7];
143
144 comptime var x2: usize = 0;
145 inline while (x2 < 8) : (x2 += 1) {
146 self.m[j + x2] = a[x2];
147 }
148 }
149 }
150
151 mem.set(u64, self.r[0..], 0);
152 self.a = 0;
153 self.b = 0;
154 self.c = 0;
155 self.i = self.r.len; // trigger refill on first value
156}
157
158fn fill(r: *Random, buf: []u8) void {
159 const self = @fieldParentPtr(Isaac64, "random", r);
160
161 var i: usize = 0;
162 const aligned_len = buf.len - (buf.len & 7);
163
164 // Fill complete 64-byte segments
165 while (i < aligned_len) : (i += 8) {
166 var n = self.next();
167 comptime var j: usize = 0;
168 inline while (j < 8) : (j += 1) {
169 buf[i + j] = @truncate(u8, n);
170 n >>= 8;
171 }
172 }
173
174 // Fill trailing, ignoring excess (cut the stream).
175 if (i != buf.len) {
176 var n = self.next();
177 while (i < buf.len) : (i += 1) {
178 buf[i] = @truncate(u8, n);
179 n >>= 8;
180 }
181 }
182}
183
184test "isaac64 sequence" {
185 var r = Isaac64.init(0);
186
187 // from reference implementation
188 const seq = [_]u64{
189 0xf67dfba498e4937c,
190 0x84a5066a9204f380,
191 0xfee34bd5f5514dbb,
192 0x4d1664739b8f80d6,
193 0x8607459ab52a14aa,
194 0x0e78bc5a98529e49,
195 0xfe5332822ad13777,
196 0x556c27525e33d01a,
197 0x08643ca615f3149f,
198 0xd0771faf3cb04714,
199 0x30e86f68a37b008d,
200 0x3074ebc0488a3adf,
201 0x270645ea7a2790bc,
202 0x5601a0a8d3763c6a,
203 0x2f83071f53f325dd,
204 0xb9090f3d42d2d2ea,
205 };
206
207 for (seq) |s| {
208 std.testing.expect(s == r.next());
209 }
210}
lib/std/rand/Pcg.zig created+101
...@@ -0,0 +1,101 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7//! PCG32 - http://www.pcg-random.org/
8//!
9//! PRNG
10
11const std = @import("std");
12const Random = std.rand.Random;
13const Pcg = @This();
14
15const default_multiplier = 6364136223846793005;
16
17random: Random,
18
19s: u64,
20i: u64,
21
22pub fn init(init_s: u64) Pcg {
23 var pcg = Pcg{
24 .random = Random{ .fillFn = fill },
25 .s = undefined,
26 .i = undefined,
27 };
28
29 pcg.seed(init_s);
30 return pcg;
31}
32
33fn next(self: *Pcg) u32 {
34 const l = self.s;
35 self.s = l *% default_multiplier +% (self.i | 1);
36
37 const xor_s = @truncate(u32, ((l >> 18) ^ l) >> 27);
38 const rot = @intCast(u32, l >> 59);
39
40 return (xor_s >> @intCast(u5, rot)) | (xor_s << @intCast(u5, (0 -% rot) & 31));
41}
42
43fn seed(self: *Pcg, init_s: u64) void {
44 // Pcg requires 128-bits of seed.
45 var gen = std.rand.SplitMix64.init(init_s);
46 self.seedTwo(gen.next(), gen.next());
47}
48
49fn seedTwo(self: *Pcg, init_s: u64, init_i: u64) void {
50 self.s = 0;
51 self.i = (init_s << 1) | 1;
52 self.s = self.s *% default_multiplier +% self.i;
53 self.s +%= init_i;
54 self.s = self.s *% default_multiplier +% self.i;
55}
56
57fn fill(r: *Random, buf: []u8) void {
58 const self = @fieldParentPtr(Pcg, "random", r);
59
60 var i: usize = 0;
61 const aligned_len = buf.len - (buf.len & 7);
62
63 // Complete 4 byte segments.
64 while (i < aligned_len) : (i += 4) {
65 var n = self.next();
66 comptime var j: usize = 0;
67 inline while (j < 4) : (j += 1) {
68 buf[i + j] = @truncate(u8, n);
69 n >>= 8;
70 }
71 }
72
73 // Remaining. (cuts the stream)
74 if (i != buf.len) {
75 var n = self.next();
76 while (i < buf.len) : (i += 1) {
77 buf[i] = @truncate(u8, n);
78 n >>= 4;
79 }
80 }
81}
82
83test "pcg sequence" {
84 var r = Pcg.init(0);
85 const s0: u64 = 0x9394bf54ce5d79de;
86 const s1: u64 = 0x84e9c579ef59bbf7;
87 r.seedTwo(s0, s1);
88
89 const seq = [_]u32{
90 2881561918,
91 3063928540,
92 1199791034,
93 2487695858,
94 1479648952,
95 3247963454,
96 };
97
98 for (seq) |s| {
99 std.testing.expect(s == r.next());
100 }
101}
lib/std/rand/Sfc64.zig created+108
...@@ -0,0 +1,108 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7//! Sfc64 pseudo-random number generator from Practically Random.
8//! Fastest engine of pracrand and smallest footprint.
9//! See http://pracrand.sourceforge.net/
10
11const std = @import("std");
12const Random = std.rand.Random;
13const math = std.math;
14const Sfc64 = @This();
15
16random: Random,
17
18a: u64 = undefined,
19b: u64 = undefined,
20c: u64 = undefined,
21counter: u64 = undefined,
22
23const Rotation = 24;
24const RightShift = 11;
25const LeftShift = 3;
26
27pub fn init(init_s: u64) Sfc64 {
28 var x = Sfc64{
29 .random = Random{ .fillFn = fill },
30 };
31
32 x.seed(init_s);
33 return x;
34}
35
36fn next(self: *Sfc64) u64 {
37 const tmp = self.a +% self.b +% self.counter;
38 self.counter += 1;
39 self.a = self.b ^ (self.b >> RightShift);
40 self.b = self.c +% (self.c << LeftShift);
41 self.c = math.rotl(u64, self.c, Rotation) +% tmp;
42 return tmp;
43}
44
45fn seed(self: *Sfc64, init_s: u64) void {
46 self.a = init_s;
47 self.b = init_s;
48 self.c = init_s;
49 self.counter = 1;
50 var i: u32 = 0;
51 while (i < 12) : (i += 1) {
52 _ = self.next();
53 }
54}
55
56fn fill(r: *Random, buf: []u8) void {
57 const self = @fieldParentPtr(Sfc64, "random", r);
58
59 var i: usize = 0;
60 const aligned_len = buf.len - (buf.len & 7);
61
62 // Complete 8 byte segments.
63 while (i < aligned_len) : (i += 8) {
64 var n = self.next();
65 comptime var j: usize = 0;
66 inline while (j < 8) : (j += 1) {
67 buf[i + j] = @truncate(u8, n);
68 n >>= 8;
69 }
70 }
71
72 // Remaining. (cuts the stream)
73 if (i != buf.len) {
74 var n = self.next();
75 while (i < buf.len) : (i += 1) {
76 buf[i] = @truncate(u8, n);
77 n >>= 8;
78 }
79 }
80}
81
82test "Sfc64 sequence" {
83 // Unfortunately there does not seem to be an official test sequence.
84 var r = Sfc64.init(0);
85
86 const seq = [_]u64{
87 0x3acfa029e3cc6041,
88 0xf5b6515bf2ee419c,
89 0x1259635894a29b61,
90 0xb6ae75395f8ebd6,
91 0x225622285ce302e2,
92 0x520d28611395cb21,
93 0xdb909c818901599d,
94 0x8ffd195365216f57,
95 0xe8c4ad5e258ac04a,
96 0x8f8ef2c89fdb63ca,
97 0xf9865b01d98d8e2f,
98 0x46555871a65d08ba,
99 0x66868677c6298fcd,
100 0x2ce15a7e6329f57d,
101 0xb2f1833ca91ca79,
102 0x4b0890ac9bf453ca,
103 };
104
105 for (seq) |s| {
106 std.testing.expectEqual(s, r.next());
107 }
108}
lib/std/rand/Xoroshiro128.zig created+133
...@@ -0,0 +1,133 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7//! Xoroshiro128+ - http://xoroshiro.di.unimi.it/
8//!
9//! PRNG
10
11const std = @import("std");
12const Random = std.rand.Random;
13const math = std.math;
14const Xoroshiro128 = @This();
15
16random: Random,
17
18s: [2]u64,
19
20pub fn init(init_s: u64) Xoroshiro128 {
21 var x = Xoroshiro128{
22 .random = Random{ .fillFn = fill },
23 .s = undefined,
24 };
25
26 x.seed(init_s);
27 return x;
28}
29
30fn next(self: *Xoroshiro128) u64 {
31 const s0 = self.s[0];
32 var s1 = self.s[1];
33 const r = s0 +% s1;
34
35 s1 ^= s0;
36 self.s[0] = math.rotl(u64, s0, @as(u8, 55)) ^ s1 ^ (s1 << 14);
37 self.s[1] = math.rotl(u64, s1, @as(u8, 36));
38
39 return r;
40}
41
42// Skip 2^64 places ahead in the sequence
43fn jump(self: *Xoroshiro128) void {
44 var s0: u64 = 0;
45 var s1: u64 = 0;
46
47 const table = [_]u64{
48 0xbeac0467eba5facb,
49 0xd86b048b86aa9922,
50 };
51
52 inline for (table) |entry| {
53 var b: usize = 0;
54 while (b < 64) : (b += 1) {
55 if ((entry & (@as(u64, 1) << @intCast(u6, b))) != 0) {
56 s0 ^= self.s[0];
57 s1 ^= self.s[1];
58 }
59 _ = self.next();
60 }
61 }
62
63 self.s[0] = s0;
64 self.s[1] = s1;
65}
66
67pub fn seed(self: *Xoroshiro128, init_s: u64) void {
68 // Xoroshiro requires 128-bits of seed.
69 var gen = std.rand.SplitMix64.init(init_s);
70
71 self.s[0] = gen.next();
72 self.s[1] = gen.next();
73}
74
75fn fill(r: *Random, buf: []u8) void {
76 const self = @fieldParentPtr(Xoroshiro128, "random", r);
77
78 var i: usize = 0;
79 const aligned_len = buf.len - (buf.len & 7);
80
81 // Complete 8 byte segments.
82 while (i < aligned_len) : (i += 8) {
83 var n = self.next();
84 comptime var j: usize = 0;
85 inline while (j < 8) : (j += 1) {
86 buf[i + j] = @truncate(u8, n);
87 n >>= 8;
88 }
89 }
90
91 // Remaining. (cuts the stream)
92 if (i != buf.len) {
93 var n = self.next();
94 while (i < buf.len) : (i += 1) {
95 buf[i] = @truncate(u8, n);
96 n >>= 8;
97 }
98 }
99}
100
101test "xoroshiro sequence" {
102 var r = Xoroshiro128.init(0);
103 r.s[0] = 0xaeecf86f7878dd75;
104 r.s[1] = 0x01cd153642e72622;
105
106 const seq1 = [_]u64{
107 0xb0ba0da5bb600397,
108 0x18a08afde614dccc,
109 0xa2635b956a31b929,
110 0xabe633c971efa045,
111 0x9ac19f9706ca3cac,
112 0xf62b426578c1e3fb,
113 };
114
115 for (seq1) |s| {
116 std.testing.expect(s == r.next());
117 }
118
119 r.jump();
120
121 const seq2 = [_]u64{
122 0x95344a13556d3e22,
123 0xb4fb32dafa4d00df,
124 0xb2011d9ccdcfe2dd,
125 0x05679a9b2119b908,
126 0xa860a1da7c9cd8a0,
127 0x658a96efe3f86550,
128 };
129
130 for (seq2) |s| {
131 std.testing.expect(s == r.next());
132 }
133}
lib/std/start.zig+26
...@@ -10,6 +10,7 @@ const std = @import("std.zig");...@@ -10,6 +10,7 @@ const std = @import("std.zig");
10const builtin = std.builtin;10const builtin = std.builtin;
11const assert = std.debug.assert;11const assert = std.debug.assert;
12const uefi = std.os.uefi;12const uefi = std.os.uefi;
13const tlcsprng = @import("crypto/tlcsprng.zig");
1314
14var argc_argv_ptr: [*]usize = undefined;15var argc_argv_ptr: [*]usize = undefined;
1516
...@@ -215,6 +216,28 @@ fn posixCallMainAndExit() noreturn {...@@ -215,6 +216,28 @@ fn posixCallMainAndExit() noreturn {
215 std.os.linux.tls.initStaticTLS();216 std.os.linux.tls.initStaticTLS();
216 }217 }
217218
219 {
220 // Initialize the per-thread CSPRNG since Linux gave us the handy-dandy
221 // AT_RANDOM. This depends on the TLS initialization above.
222 var i: usize = 0;
223 while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) {
224 switch (auxv[i].a_type) {
225 std.elf.AT_RANDOM => {
226 // "The address of sixteen bytes containing a random value."
227 const addr = auxv[i].a_un.a_val;
228 if (addr == 0) break;
229 const ptr = @intToPtr(*const [16]u8, addr);
230 var seed: [32]u8 = undefined;
231 seed[0..16].* = ptr.*;
232 seed[16..].* = ptr.*;
233 tlcsprng.init(seed);
234 break;
235 },
236 else => continue,
237 }
238 }
239 }
240
218 // TODO This is disabled because what should we do when linking libc and this code241 // TODO This is disabled because what should we do when linking libc and this code
219 // does not execute? And also it's causing a test failure in stack traces in release modes.242 // does not execute? And also it's causing a test failure in stack traces in release modes.
220243
...@@ -250,6 +273,9 @@ fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 {...@@ -250,6 +273,9 @@ fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 {
250}273}
251274
252fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C) i32 {275fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C) i32 {
276 // We do not attempt to initialize tlcsprng from AT_RANDOM here because
277 // libc owns the start code, not us, and therefore libc ows the random bytes
278 // from AT_RANDOM.
253 var env_count: usize = 0;279 var env_count: usize = 0;
254 while (c_envp[env_count] != null) : (env_count += 1) {}280 while (c_envp[env_count] != null) : (env_count += 1) {}
255 const envp = @ptrCast([*][*:0]u8, c_envp)[0..env_count];281 const envp = @ptrCast([*][*:0]u8, c_envp)[0..env_count];
lib/std/testing.zig+1-2
...@@ -303,8 +303,7 @@ fn getCwdOrWasiPreopen() std.fs.Dir {...@@ -303,8 +303,7 @@ fn getCwdOrWasiPreopen() std.fs.Dir {
303303
304pub fn tmpDir(opts: std.fs.Dir.OpenDirOptions) TmpDir {304pub fn tmpDir(opts: std.fs.Dir.OpenDirOptions) TmpDir {
305 var random_bytes: [TmpDir.random_bytes_count]u8 = undefined;305 var random_bytes: [TmpDir.random_bytes_count]u8 = undefined;
306 std.crypto.randomBytes(&random_bytes) catch306 std.crypto.random.bytes(&random_bytes);
307 @panic("unable to make tmp dir for testing: unable to get random bytes");
308 var sub_path: [TmpDir.sub_path_len]u8 = undefined;307 var sub_path: [TmpDir.sub_path_len]u8 = undefined;
309 std.fs.base64_encoder.encode(&sub_path, &random_bytes);308 std.fs.base64_encoder.encode(&sub_path, &random_bytes);
310309
src/Compilation.zig+1-6
...@@ -74,7 +74,6 @@ zig_lib_directory: Directory,...@@ -74,7 +74,6 @@ zig_lib_directory: Directory,
74local_cache_directory: Directory,74local_cache_directory: Directory,
75global_cache_directory: Directory,75global_cache_directory: Directory,
76libc_include_dir_list: []const []const u8,76libc_include_dir_list: []const []const u8,
77rand: *std.rand.Random,
7877
79/// Populated when we build the libc++ static library. A Job to build this is placed in the queue78/// Populated when we build the libc++ static library. A Job to build this is placed in the queue
80/// and resolved before calling linker.flush().79/// and resolved before calling linker.flush().
...@@ -331,7 +330,6 @@ pub const InitOptions = struct {...@@ -331,7 +330,6 @@ pub const InitOptions = struct {
331 root_name: []const u8,330 root_name: []const u8,
332 root_pkg: ?*Package,331 root_pkg: ?*Package,
333 output_mode: std.builtin.OutputMode,332 output_mode: std.builtin.OutputMode,
334 rand: *std.rand.Random,
335 dynamic_linker: ?[]const u8 = null,333 dynamic_linker: ?[]const u8 = null,
336 /// `null` means to not emit a binary file.334 /// `null` means to not emit a binary file.
337 emit_bin: ?EmitLoc,335 emit_bin: ?EmitLoc,
...@@ -981,7 +979,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -981,7 +979,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
981 .self_exe_path = options.self_exe_path,979 .self_exe_path = options.self_exe_path,
982 .libc_include_dir_list = libc_dirs.libc_include_dir_list,980 .libc_include_dir_list = libc_dirs.libc_include_dir_list,
983 .sanitize_c = sanitize_c,981 .sanitize_c = sanitize_c,
984 .rand = options.rand,
985 .clang_passthrough_mode = options.clang_passthrough_mode,982 .clang_passthrough_mode = options.clang_passthrough_mode,
986 .clang_preprocessor_mode = options.clang_preprocessor_mode,983 .clang_preprocessor_mode = options.clang_preprocessor_mode,
987 .verbose_cc = options.verbose_cc,984 .verbose_cc = options.verbose_cc,
...@@ -1909,7 +1906,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: *...@@ -1909,7 +1906,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: *
19091906
1910pub fn tmpFilePath(comp: *Compilation, arena: *Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 {1907pub fn tmpFilePath(comp: *Compilation, arena: *Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 {
1911 const s = std.fs.path.sep_str;1908 const s = std.fs.path.sep_str;
1912 const rand_int = comp.rand.int(u64);1909 const rand_int = std.crypto.random.int(u64);
1913 if (comp.local_cache_directory.path) |p| {1910 if (comp.local_cache_directory.path) |p| {
1914 return std.fmt.allocPrint(arena, "{}" ++ s ++ "tmp" ++ s ++ "{x}-{s}", .{ p, rand_int, suffix });1911 return std.fmt.allocPrint(arena, "{}" ++ s ++ "tmp" ++ s ++ "{x}-{s}", .{ p, rand_int, suffix });
1915 } else {1912 } else {
...@@ -2778,7 +2775,6 @@ fn buildOutputFromZig(...@@ -2778,7 +2775,6 @@ fn buildOutputFromZig(
2778 .root_name = root_name,2775 .root_name = root_name,
2779 .root_pkg = &root_pkg,2776 .root_pkg = &root_pkg,
2780 .output_mode = fixed_output_mode,2777 .output_mode = fixed_output_mode,
2781 .rand = comp.rand,
2782 .libc_installation = comp.bin_file.options.libc_installation,2778 .libc_installation = comp.bin_file.options.libc_installation,
2783 .emit_bin = emit_bin,2779 .emit_bin = emit_bin,
2784 .optimize_mode = optimize_mode,2780 .optimize_mode = optimize_mode,
...@@ -3152,7 +3148,6 @@ pub fn build_crt_file(...@@ -3152,7 +3148,6 @@ pub fn build_crt_file(
3152 .root_name = root_name,3148 .root_name = root_name,
3153 .root_pkg = null,3149 .root_pkg = null,
3154 .output_mode = output_mode,3150 .output_mode = output_mode,
3155 .rand = comp.rand,
3156 .libc_installation = comp.bin_file.options.libc_installation,3151 .libc_installation = comp.bin_file.options.libc_installation,
3157 .emit_bin = emit_bin,3152 .emit_bin = emit_bin,
3158 .optimize_mode = comp.bin_file.options.optimize_mode,3153 .optimize_mode = comp.bin_file.options.optimize_mode,
src/glibc.zig-1
...@@ -936,7 +936,6 @@ fn buildSharedLib(...@@ -936,7 +936,6 @@ fn buildSharedLib(
936 .root_pkg = null,936 .root_pkg = null,
937 .output_mode = .Lib,937 .output_mode = .Lib,
938 .link_mode = .Dynamic,938 .link_mode = .Dynamic,
939 .rand = comp.rand,
940 .libc_installation = comp.bin_file.options.libc_installation,939 .libc_installation = comp.bin_file.options.libc_installation,
941 .emit_bin = emit_bin,940 .emit_bin = emit_bin,
942 .optimize_mode = comp.bin_file.options.optimize_mode,941 .optimize_mode = comp.bin_file.options.optimize_mode,
src/libcxx.zig-2
...@@ -162,7 +162,6 @@ pub fn buildLibCXX(comp: *Compilation) !void {...@@ -162,7 +162,6 @@ pub fn buildLibCXX(comp: *Compilation) !void {
162 .root_name = root_name,162 .root_name = root_name,
163 .root_pkg = null,163 .root_pkg = null,
164 .output_mode = output_mode,164 .output_mode = output_mode,
165 .rand = comp.rand,
166 .libc_installation = comp.bin_file.options.libc_installation,165 .libc_installation = comp.bin_file.options.libc_installation,
167 .emit_bin = emit_bin,166 .emit_bin = emit_bin,
168 .optimize_mode = comp.bin_file.options.optimize_mode,167 .optimize_mode = comp.bin_file.options.optimize_mode,
...@@ -281,7 +280,6 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {...@@ -281,7 +280,6 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {
281 .root_name = root_name,280 .root_name = root_name,
282 .root_pkg = null,281 .root_pkg = null,
283 .output_mode = output_mode,282 .output_mode = output_mode,
284 .rand = comp.rand,
285 .libc_installation = comp.bin_file.options.libc_installation,283 .libc_installation = comp.bin_file.options.libc_installation,
286 .emit_bin = emit_bin,284 .emit_bin = emit_bin,
287 .optimize_mode = comp.bin_file.options.optimize_mode,285 .optimize_mode = comp.bin_file.options.optimize_mode,
src/libunwind.zig-1
...@@ -95,7 +95,6 @@ pub fn buildStaticLib(comp: *Compilation) !void {...@@ -95,7 +95,6 @@ pub fn buildStaticLib(comp: *Compilation) !void {
95 .root_name = root_name,95 .root_name = root_name,
96 .root_pkg = null,96 .root_pkg = null,
97 .output_mode = output_mode,97 .output_mode = output_mode,
98 .rand = comp.rand,
99 .libc_installation = comp.bin_file.options.libc_installation,98 .libc_installation = comp.bin_file.options.libc_installation,
100 .emit_bin = emit_bin,99 .emit_bin = emit_bin,
101 .optimize_mode = comp.bin_file.options.optimize_mode,100 .optimize_mode = comp.bin_file.options.optimize_mode,
src/main.zig-15
...@@ -1632,13 +1632,6 @@ fn buildOutputType(...@@ -1632,13 +1632,6 @@ fn buildOutputType(
1632 };1632 };
1633 defer zig_lib_directory.handle.close();1633 defer zig_lib_directory.handle.close();
16341634
1635 const random_seed = blk: {
1636 var random_seed: u64 = undefined;
1637 try std.crypto.randomBytes(mem.asBytes(&random_seed));
1638 break :blk random_seed;
1639 };
1640 var default_prng = std.rand.DefaultPrng.init(random_seed);
1641
1642 var libc_installation: ?LibCInstallation = null;1635 var libc_installation: ?LibCInstallation = null;
1643 defer if (libc_installation) |*l| l.deinit(gpa);1636 defer if (libc_installation) |*l| l.deinit(gpa);
16441637
...@@ -1754,7 +1747,6 @@ fn buildOutputType(...@@ -1754,7 +1747,6 @@ fn buildOutputType(
1754 .single_threaded = single_threaded,1747 .single_threaded = single_threaded,
1755 .function_sections = function_sections,1748 .function_sections = function_sections,
1756 .self_exe_path = self_exe_path,1749 .self_exe_path = self_exe_path,
1757 .rand = &default_prng.random,
1758 .clang_passthrough_mode = arg_mode != .build,1750 .clang_passthrough_mode = arg_mode != .build,
1759 .clang_preprocessor_mode = clang_preprocessor_mode,1751 .clang_preprocessor_mode = clang_preprocessor_mode,
1760 .version = optional_version,1752 .version = optional_version,
...@@ -2420,12 +2412,6 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v...@@ -2420,12 +2412,6 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
2420 .directory = null, // Use the local zig-cache.2412 .directory = null, // Use the local zig-cache.
2421 .basename = exe_basename,2413 .basename = exe_basename,
2422 };2414 };
2423 const random_seed = blk: {
2424 var random_seed: u64 = undefined;
2425 try std.crypto.randomBytes(mem.asBytes(&random_seed));
2426 break :blk random_seed;
2427 };
2428 var default_prng = std.rand.DefaultPrng.init(random_seed);
2429 const comp = Compilation.create(gpa, .{2415 const comp = Compilation.create(gpa, .{
2430 .zig_lib_directory = zig_lib_directory,2416 .zig_lib_directory = zig_lib_directory,
2431 .local_cache_directory = local_cache_directory,2417 .local_cache_directory = local_cache_directory,
...@@ -2441,7 +2427,6 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v...@@ -2441,7 +2427,6 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
2441 .emit_h = null,2427 .emit_h = null,
2442 .optimize_mode = .Debug,2428 .optimize_mode = .Debug,
2443 .self_exe_path = self_exe_path,2429 .self_exe_path = self_exe_path,
2444 .rand = &default_prng.random,
2445 }) catch |err| {2430 }) catch |err| {
2446 fatal("unable to create compilation: {}", .{@errorName(err)});2431 fatal("unable to create compilation: {}", .{@errorName(err)});
2447 };2432 };
src/musl.zig-1
...@@ -200,7 +200,6 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -200,7 +200,6 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
200 .root_pkg = null,200 .root_pkg = null,
201 .output_mode = .Lib,201 .output_mode = .Lib,
202 .link_mode = .Dynamic,202 .link_mode = .Dynamic,
203 .rand = comp.rand,
204 .libc_installation = comp.bin_file.options.libc_installation,203 .libc_installation = comp.bin_file.options.libc_installation,
205 .emit_bin = Compilation.EmitLoc{ .directory = null, .basename = "libc.so" },204 .emit_bin = Compilation.EmitLoc{ .directory = null, .basename = "libc.so" },
206 .optimize_mode = comp.bin_file.options.optimize_mode,205 .optimize_mode = comp.bin_file.options.optimize_mode,
src/test.zig+1-10
...@@ -467,13 +467,6 @@ pub const TestContext = struct {...@@ -467,13 +467,6 @@ pub const TestContext = struct {
467 defer zig_lib_directory.handle.close();467 defer zig_lib_directory.handle.close();
468 defer std.testing.allocator.free(zig_lib_directory.path.?);468 defer std.testing.allocator.free(zig_lib_directory.path.?);
469469
470 const random_seed = blk: {
471 var random_seed: u64 = undefined;
472 try std.crypto.randomBytes(std.mem.asBytes(&random_seed));
473 break :blk random_seed;
474 };
475 var default_prng = std.rand.DefaultPrng.init(random_seed);
476
477 for (self.cases.items) |case| {470 for (self.cases.items) |case| {
478 if (build_options.skip_non_native and case.target.getCpuArch() != std.Target.current.cpu.arch)471 if (build_options.skip_non_native and case.target.getCpuArch() != std.Target.current.cpu.arch)
479 continue;472 continue;
...@@ -487,7 +480,7 @@ pub const TestContext = struct {...@@ -487,7 +480,7 @@ pub const TestContext = struct {
487 progress.initial_delay_ns = 0;480 progress.initial_delay_ns = 0;
488 progress.refresh_rate_ns = 0;481 progress.refresh_rate_ns = 0;
489482
490 try self.runOneCase(std.testing.allocator, &prg_node, case, zig_lib_directory, &default_prng.random);483 try self.runOneCase(std.testing.allocator, &prg_node, case, zig_lib_directory);
491 }484 }
492 }485 }
493486
...@@ -497,7 +490,6 @@ pub const TestContext = struct {...@@ -497,7 +490,6 @@ pub const TestContext = struct {
497 root_node: *std.Progress.Node,490 root_node: *std.Progress.Node,
498 case: Case,491 case: Case,
499 zig_lib_directory: Compilation.Directory,492 zig_lib_directory: Compilation.Directory,
500 rand: *std.rand.Random,
501 ) !void {493 ) !void {
502 const target_info = try std.zig.system.NativeTargetInfo.detect(allocator, case.target);494 const target_info = try std.zig.system.NativeTargetInfo.detect(allocator, case.target);
503 const target = target_info.target;495 const target = target_info.target;
...@@ -547,7 +539,6 @@ pub const TestContext = struct {...@@ -547,7 +539,6 @@ pub const TestContext = struct {
547 .local_cache_directory = zig_cache_directory,539 .local_cache_directory = zig_cache_directory,
548 .global_cache_directory = zig_cache_directory,540 .global_cache_directory = zig_cache_directory,
549 .zig_lib_directory = zig_lib_directory,541 .zig_lib_directory = zig_lib_directory,
550 .rand = rand,
551 .root_name = "test_case",542 .root_name = "test_case",
552 .target = target,543 .target = target,
553 // TODO: support tests for object file building, and library builds544 // TODO: support tests for object file building, and library builds