| author | |
| committer | |
| log | 013efaf13987acfa6b41d40f07900c1ea77f5bda |
| tree | 14325d114eb66312b3545f3a897142400dfb7c16 |
| parent | ce65533985caa9e2da567948e36d7d4ba0185005 |
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 #670424 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 { |
| 134 | 134 | ||
| 135 | pub const utils = @import("crypto/utils.zig"); | 135 | pub const utils = @import("crypto/utils.zig"); |
| 136 | 136 | ||
| 137 | /// This is a thread-local, cryptographically secure pseudo random number generator. | ||
| 138 | pub const random = &@import("crypto/tlcsprng.zig").interface; | ||
| 139 | |||
| 137 | const std = @import("std.zig"); | 140 | const std = @import("std.zig"); |
| 138 | pub const randomBytes = std.os.getrandom; | ||
| 139 | 141 | ||
| 140 | test "crypto" { | 142 | test "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 | } |
| 180 | 182 | ||
| 183 | test "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 | |||
| 181 | test "issue #4532: no index out of bounds" { | 190 | test "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 { |
| 179 | 179 | ||
| 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 | } |
| 185 | 185 | ||
| ... | @@ -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" { |
| 484 | test "edwards25519 point addition/substraction" { | 484 | test "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. |
| 263 | pub fn strHash(password: []const u8, rounds_log: u6) ![hash_length]u8 { | 263 | pub 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 | } |
| 268 | 268 | ||
| ... | @@ -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 { |
| 283 | 283 | ||
| 284 | test "bcrypt codec" { | 284 | test "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); |
| 577 | 577 | ||
| 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); |
| 591 | 591 | ||
| 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); |
| 603 | 603 | ||
| 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); |
| 615 | 615 | ||
| 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 | |||
| 12 | const std = @import("std"); | ||
| 13 | const root = @import("root"); | ||
| 14 | const mem = std.mem; | ||
| 15 | |||
| 16 | /// We use this as a layer of indirection because global const pointers cannot | ||
| 17 | /// point to thread-local variables. | ||
| 18 | pub var interface = std.rand.Random{ .fillFn = tlsCsprngFill }; | ||
| 19 | pub threadlocal var csprng_state: std.crypto.core.Gimli = undefined; | ||
| 20 | pub threadlocal var csprng_state_initialized = false; | ||
| 21 | fn 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 | |||
| 47 | fn defaultSeed(buffer: *[seed_len]u8) void { | ||
| 48 | std.os.getrandom(buffer) catch @panic("getrandom() failed to seed thread-local CSPRNG"); | ||
| 49 | } | ||
| 50 | |||
| 51 | pub const seed_len = 32; | ||
| 52 | |||
| 53 | pub 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 { |
| 51 | test "crypto.utils.timingSafeEql" { | 51 | test "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" { |
| 61 | test "crypto.utils.timingSafeEql (vectors)" { | 61 | test "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); |
| 87 | 87 | ||
| 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; |
| 158 | 158 | ||
| 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); |
| 162 | 162 | ||
| 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 copies | 4 | // 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. |
| 6 | 6 | ||
| 7 | //! The engines provided here should be initialized from an external source. For now, randomBytes | 7 | //! 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 using | 8 | //! 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. |
| 22 | 14 | ||
| ... | @@ -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. |
| 37 | pub const DefaultCsprng = Gimli; | 29 | pub const DefaultCsprng = Gimli; |
| 38 | 30 | ||
| 31 | pub const Isaac64 = @import("rand/Isaac64.zig"); | ||
| 32 | pub const Gimli = @import("rand/Gimli.zig"); | ||
| 33 | pub const Pcg = @import("rand/Pcg.zig"); | ||
| 34 | pub const Xoroshiro128 = @import("rand/Xoroshiro128.zig"); | ||
| 35 | pub const Sfc64 = @import("rand/Sfc64.zig"); | ||
| 36 | |||
| 39 | pub const Random = struct { | 37 | pub const Random = struct { |
| 40 | fillFn: fn (r: *Random, buf: []u8) void, | 38 | fillFn: fn (r: *Random, buf: []u8) void, |
| 41 | 39 | ||
| ... | @@ -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 this | 490 | // 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. |
| 494 | const SplitMix64 = struct { | 492 | pub const SplitMix64 = struct { |
| 495 | s: u64, | 493 | s: u64, |
| 496 | 494 | ||
| 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 | } |
| 527 | 525 | ||
| 528 | // PCG32 - http://www.pcg-random.org/ | ||
| 529 | // | ||
| 530 | // PRNG | ||
| 531 | pub 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 | |||
| 601 | test "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 | ||
| 624 | pub 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 | |||
| 711 | test "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 | ||
| 748 | pub 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 | ||
| 783 | pub 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 | |||
| 952 | test "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/ | ||
| 983 | pub 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 | |||
| 1051 | test "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. |
| 1080 | test "Random float" { | 527 | test "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 { |
| 1147 | 594 | ||
| 1148 | test "CSPRNG" { | 595 | test "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 | |||
| 9 | const std = @import("std"); | ||
| 10 | const Random = std.rand.Random; | ||
| 11 | const mem = std.mem; | ||
| 12 | const Gimli = @This(); | ||
| 13 | |||
| 14 | random: Random, | ||
| 15 | state: std.crypto.core.Gimli, | ||
| 16 | |||
| 17 | pub const secret_seed_length = 32; | ||
| 18 | |||
| 19 | /// The seed must be uniform, secret and `secret_seed_length` bytes long. | ||
| 20 | pub 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 | |||
| 31 | fn 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 | |||
| 12 | const std = @import("std"); | ||
| 13 | const Random = std.rand.Random; | ||
| 14 | const mem = std.mem; | ||
| 15 | const Isaac64 = @This(); | ||
| 16 | |||
| 17 | random: Random, | ||
| 18 | |||
| 19 | r: [256]u64, | ||
| 20 | m: [256]u64, | ||
| 21 | a: u64, | ||
| 22 | b: u64, | ||
| 23 | c: u64, | ||
| 24 | i: usize, | ||
| 25 | |||
| 26 | pub 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 | |||
| 42 | fn 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 | |||
| 53 | fn 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 | |||
| 82 | fn 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 | |||
| 92 | fn 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 | |||
| 158 | fn 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 | |||
| 184 | test "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 | |||
| 11 | const std = @import("std"); | ||
| 12 | const Random = std.rand.Random; | ||
| 13 | const Pcg = @This(); | ||
| 14 | |||
| 15 | const default_multiplier = 6364136223846793005; | ||
| 16 | |||
| 17 | random: Random, | ||
| 18 | |||
| 19 | s: u64, | ||
| 20 | i: u64, | ||
| 21 | |||
| 22 | pub 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 | |||
| 33 | fn 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 | |||
| 43 | fn 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 | |||
| 49 | fn 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 | |||
| 57 | fn 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 | |||
| 83 | test "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 | |||
| 11 | const std = @import("std"); | ||
| 12 | const Random = std.rand.Random; | ||
| 13 | const math = std.math; | ||
| 14 | const Sfc64 = @This(); | ||
| 15 | |||
| 16 | random: Random, | ||
| 17 | |||
| 18 | a: u64 = undefined, | ||
| 19 | b: u64 = undefined, | ||
| 20 | c: u64 = undefined, | ||
| 21 | counter: u64 = undefined, | ||
| 22 | |||
| 23 | const Rotation = 24; | ||
| 24 | const RightShift = 11; | ||
| 25 | const LeftShift = 3; | ||
| 26 | |||
| 27 | pub 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 | |||
| 36 | fn 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 | |||
| 45 | fn 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 | |||
| 56 | fn 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 | |||
| 82 | test "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 | |||
| 11 | const std = @import("std"); | ||
| 12 | const Random = std.rand.Random; | ||
| 13 | const math = std.math; | ||
| 14 | const Xoroshiro128 = @This(); | ||
| 15 | |||
| 16 | random: Random, | ||
| 17 | |||
| 18 | s: [2]u64, | ||
| 19 | |||
| 20 | pub 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 | |||
| 30 | fn 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 | ||
| 43 | fn 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 | |||
| 67 | pub 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 | |||
| 75 | fn 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 | |||
| 101 | test "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"); |
| 10 | const builtin = std.builtin; | 10 | const builtin = std.builtin; |
| 11 | const assert = std.debug.assert; | 11 | const assert = std.debug.assert; |
| 12 | const uefi = std.os.uefi; | 12 | const uefi = std.os.uefi; |
| 13 | const tlcsprng = @import("crypto/tlcsprng.zig"); | ||
| 13 | 14 | ||
| 14 | var argc_argv_ptr: [*]usize = undefined; | 15 | var argc_argv_ptr: [*]usize = undefined; |
| 15 | 16 | ||
| ... | @@ -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 | } |
| 217 | 218 | ||
| 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 code | 241 | // 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. |
| 220 | 243 | ||
| ... | @@ -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 | } |
| 251 | 274 | ||
| 252 | fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C) i32 { | 275 | fn 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 { |
| 303 | 303 | ||
| 304 | pub fn tmpDir(opts: std.fs.Dir.OpenDirOptions) TmpDir { | 304 | pub 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) catch | 306 | 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); |
| 310 | 309 |
src/Compilation.zig+1-6| ... | @@ -74,7 +74,6 @@ zig_lib_directory: Directory, | ... | @@ -74,7 +74,6 @@ zig_lib_directory: Directory, |
| 74 | local_cache_directory: Directory, | 74 | local_cache_directory: Directory, |
| 75 | global_cache_directory: Directory, | 75 | global_cache_directory: Directory, |
| 76 | libc_include_dir_list: []const []const u8, | 76 | libc_include_dir_list: []const []const u8, |
| 77 | rand: *std.rand.Random, | ||
| 78 | 77 | ||
| 79 | /// Populated when we build the libc++ static library. A Job to build this is placed in the queue | 78 | /// 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: * |
| 1909 | 1906 | ||
| 1910 | pub fn tmpFilePath(comp: *Compilation, arena: *Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 { | 1907 | pub 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(); |
| 1634 | 1634 | ||
| 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); |
| 1644 | 1637 | ||
| ... | @@ -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.?); |
| 469 | 469 | ||
| 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; |
| 489 | 482 | ||
| 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 | } |
| 493 | 486 | ||
| ... | @@ -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 builds | 544 | // TODO: support tests for object file building, and library builds |