authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-05 20:42:37-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-07 11:03:36-08:00
log1f1381a866a110953f9950d8c0c6497a2567daa0
tree458e258f1ea98c691ebbd41b353c65b676b4ff8a
parent81a35a86ea9385016f371213a2b72b14902bb955

update API usage of std.crypto.random to io.random


45 files changed, 514 insertions(+), 336 deletions(-)

lib/compiler/aro/aro/Driver.zig+2-1
......@@ -1217,11 +1217,12 @@ pub fn getDepFileName(d: *Driver, source: Source, buf: *[std.fs.max_name_bytes]u
12171217}
12181218
12191219fn getRandomFilename(d: *Driver, buf: *[std.fs.max_name_bytes]u8, extension: []const u8) ![]const u8 {
1220 const io = d.comp.io;
12201221 const random_bytes_count = 12;
12211222 const sub_path_len = comptime std.fs.base64_encoder.calcSize(random_bytes_count);
12221223
12231224 var random_bytes: [random_bytes_count]u8 = undefined;
1224 std.crypto.random.bytes(&random_bytes);
1225 io.random(&random_bytes);
12251226 var random_name: [sub_path_len]u8 = undefined;
12261227 _ = std.fs.base64_encoder.encode(&random_name, &random_bytes);
12271228
lib/std/Io/Threaded.zig+49-16
......@@ -78,7 +78,7 @@ pub const Csprng = struct {
7878 pub const seed_len = std.Random.DefaultCsprng.secret_seed_length;
7979
8080 pub fn isInitialized(c: *const Csprng) bool {
81 return c.rng.offset == std.math.maxInt(usize);
81 return c.rng.offset != std.math.maxInt(usize);
8282 }
8383};
8484
......@@ -2395,11 +2395,11 @@ fn dirCreateDirPath(
23952395 status = .created;
23962396 } else |err| switch (err) {
23972397 error.PathAlreadyExists => {
2398 // stat the file and return an error if it's not a directory
2399 // this is important because otherwise a dangling symlink
2400 // could cause an infinite loop
2401 const fstat = try dirStatFile(t, dir, component.path, .{});
2402 if (fstat.kind != .directory) return error.NotDir;
2398 // It is important to return an error if it's not a directory
2399 // because otherwise a dangling symlink could cause an infinite
2400 // loop.
2401 const kind = try filePathKind(t, dir, component.path);
2402 if (kind != .directory) return error.NotDir;
24032403 },
24042404 error.FileNotFound => |e| {
24052405 component = it.previous() orelse return e;
......@@ -2740,6 +2740,35 @@ fn dirStatFileWasi(
27402740 }
27412741}
27422742
2743fn filePathKind(t: *Threaded, dir: Dir, sub_path: []const u8) !File.Kind {
2744 if (native_os == .linux) {
2745 var path_buffer: [posix.PATH_MAX]u8 = undefined;
2746 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
2747
2748 const linux = std.os.linux;
2749 const syscall: Syscall = try .start();
2750 while (true) {
2751 var statx = std.mem.zeroes(linux.Statx);
2752 switch (linux.errno(linux.statx(dir.handle, sub_path_posix, 0, .{ .TYPE = true }, &statx))) {
2753 .SUCCESS => {
2754 syscall.finish();
2755 if (!statx.mask.TYPE) return error.Unexpected;
2756 return statxKind(statx.mode);
2757 },
2758 .INTR => {
2759 try syscall.checkCancel();
2760 continue;
2761 },
2762 .NOMEM => return syscall.fail(error.SystemResources),
2763 else => |err| return syscall.unexpectedErrno(err),
2764 }
2765 }
2766 }
2767
2768 const stat = try dirStatFile(t, dir, sub_path, .{});
2769 return stat.kind;
2770}
2771
27432772fn fileLength(userdata: ?*anyopaque, file: File) File.LengthError!u64 {
27442773 const t: *Threaded = @ptrCast(@alignCast(userdata));
27452774
......@@ -12310,16 +12339,7 @@ fn statFromLinux(stx: *const std.os.linux.Statx) Io.UnexpectedError!File.Stat {
1231012339 .nlink = stx.nlink,
1231112340 .size = stx.size,
1231212341 .permissions = .fromMode(stx.mode),
12313 .kind = switch (stx.mode & std.os.linux.S.IFMT) {
12314 std.os.linux.S.IFDIR => .directory,
12315 std.os.linux.S.IFCHR => .character_device,
12316 std.os.linux.S.IFBLK => .block_device,
12317 std.os.linux.S.IFREG => .file,
12318 std.os.linux.S.IFIFO => .named_pipe,
12319 std.os.linux.S.IFLNK => .sym_link,
12320 std.os.linux.S.IFSOCK => .unix_domain_socket,
12321 else => .unknown,
12322 },
12342 .kind = statxKind(stx.mode),
1232312343 .atime = if (!stx.mask.ATIME) null else .{
1232412344 .nanoseconds = @intCast(@as(i128, stx.atime.sec) * std.time.ns_per_s + stx.atime.nsec),
1232512345 },
......@@ -12328,6 +12348,19 @@ fn statFromLinux(stx: *const std.os.linux.Statx) Io.UnexpectedError!File.Stat {
1232812348 };
1232912349}
1233012350
12351fn statxKind(stx_mode: u16) File.Kind {
12352 return switch (stx_mode & std.os.linux.S.IFMT) {
12353 std.os.linux.S.IFDIR => .directory,
12354 std.os.linux.S.IFCHR => .character_device,
12355 std.os.linux.S.IFBLK => .block_device,
12356 std.os.linux.S.IFREG => .file,
12357 std.os.linux.S.IFIFO => .named_pipe,
12358 std.os.linux.S.IFLNK => .sym_link,
12359 std.os.linux.S.IFSOCK => .unix_domain_socket,
12360 else => .unknown,
12361 };
12362}
12363
1233112364fn statFromPosix(st: *const posix.Stat) File.Stat {
1233212365 const atime = st.atime();
1233312366 const mtime = st.mtime();
lib/std/Io/net/test.zig+3-3
......@@ -275,7 +275,7 @@ test "listen on a unix socket, send bytes, receive bytes" {
275275
276276 const io = testing.io;
277277
278 const socket_path = try generateFileName("socket.unix");
278 const socket_path = try generateFileName(io, "socket.unix");
279279 defer testing.allocator.free(socket_path);
280280
281281 const socket_addr = try net.UnixAddress.init(socket_path);
......@@ -308,11 +308,11 @@ test "listen on a unix socket, send bytes, receive bytes" {
308308 try testing.expectEqualSlices(u8, "Hello world!", buf[0..n]);
309309}
310310
311fn generateFileName(base_name: []const u8) ![]const u8 {
311fn generateFileName(io: Io, base_name: []const u8) ![]const u8 {
312312 const random_bytes_count = 12;
313313 const sub_path_len = comptime std.fs.base64_encoder.calcSize(random_bytes_count);
314314 var random_bytes: [12]u8 = undefined;
315 std.crypto.random.bytes(&random_bytes);
315 io.random(&random_bytes);
316316 var sub_path: [sub_path_len]u8 = undefined;
317317 _ = std.fs.base64_encoder.encode(&sub_path, &random_bytes);
318318 return std.fmt.allocPrint(testing.allocator, "{s}-{s}", .{ sub_path[0..], base_name });
lib/std/Io/test.zig+20-5
......@@ -565,13 +565,28 @@ test "tasks spawned in group after Group.cancel are canceled" {
565565 try group.concurrent(io, global.waitThenSpawn, .{ io, &group });
566566}
567567
568test "CSPRNG" {
568test "random" {
569569 const io = testing.io;
570570
571 var random = io.random();
571 var a: u64 = undefined;
572 var b: u64 = undefined;
573 var c: u64 = undefined;
574
575 io.random(@ptrCast(&a));
576 io.random(@ptrCast(&b));
577 io.random(@ptrCast(&c));
572578
573 const a = random.int(u64);
574 const b = random.int(u64);
575 const c = random.int(u64);
576579 try std.testing.expect(a ^ b ^ c != 0);
577580}
581
582test "randomSecure" {
583 const io = testing.io;
584
585 var buf_a: [50]u8 = undefined;
586 var buf_b: [50]u8 = undefined;
587 try io.randomSecure(&buf_a);
588 try io.randomSecure(&buf_b);
589 // If this test fails the chance is significantly higher that there is a bug than
590 // that two sets of 50 bytes were equal.
591 try expect(!mem.eql(u8, &buf_a, &buf_b));
592}
lib/std/Random.zig+1-1
......@@ -38,7 +38,7 @@ pub const IoSource = struct {
3838
3939 pub fn interface(this: *const @This()) std.Random {
4040 return .{
41 .ptr = this,
41 .ptr = @constCast(this),
4242 .fillFn = fill,
4343 };
4444 }
lib/std/Random/test.zig+2-1
......@@ -436,8 +436,9 @@ fn testRangeBias(r: Random, start: i8, end: i8, biased: bool) !void {
436436}
437437
438438test "CSPRNG" {
439 const io = std.testing.io;
439440 var secret_seed: [DefaultCsprng.secret_seed_length]u8 = undefined;
440 std.crypto.random.bytes(&secret_seed);
441 io.random(&secret_seed);
441442 var csprng = DefaultCsprng.init(secret_seed);
442443 const random = csprng.random();
443444 const a = random.int(u64);
lib/std/crypto.zig+4
......@@ -303,6 +303,9 @@ test {
303303 _ = dh.X25519;
304304
305305 _ = kem.kyber_d00;
306 _ = kem.hybrid;
307 _ = kem.kyber_d00;
308 _ = kem.ml_kem;
306309
307310 _ = ecc.Curve25519;
308311 _ = ecc.Edwards25519;
......@@ -340,6 +343,7 @@ test {
340343
341344 _ = sign.Ed25519;
342345 _ = sign.ecdsa;
346 _ = sign.mldsa;
343347
344348 _ = stream.chacha.ChaCha20IETF;
345349 _ = stream.chacha.ChaCha12IETF;
lib/std/crypto/25519/ed25519.zig+32-23
......@@ -333,12 +333,10 @@ pub const Ed25519 = struct {
333333 }
334334
335335 /// Generate a new, random key pair.
336 ///
337 /// `crypto.random.bytes` must be supported by the target.
338 pub fn generate() KeyPair {
336 pub fn generate(io: std.Io) KeyPair {
339337 var random_seed: [seed_length]u8 = undefined;
340338 while (true) {
341 crypto.random.bytes(&random_seed);
339 io.random(&random_seed);
342340 return generateDeterministic(random_seed) catch {
343341 @branchHint(.unlikely);
344342 continue;
......@@ -389,18 +387,21 @@ pub const Ed25519 = struct {
389387
390388 /// Create a Signer, that can be used for incremental signing.
391389 /// Note that the signature is not deterministic.
392 /// The noise parameter, if set, should be something unique for each message,
393 /// such as a random nonce, or a counter.
394 pub fn signer(key_pair: KeyPair, noise: ?[noise_length]u8) (IdentityElementError || KeyMismatchError || NonCanonicalError || WeakPublicKeyError)!Signer {
390 pub fn signer(
391 key_pair: KeyPair,
392 /// If set, should be something unique for each message, such as a
393 /// random nonce, or a counter.
394 noise: ?[noise_length]u8,
395 /// Filled with cryptographically secure randomness.
396 entropy: *const [noise_length]u8,
397 ) (IdentityElementError || KeyMismatchError || NonCanonicalError || WeakPublicKeyError)!Signer {
395398 if (!mem.eql(u8, &key_pair.secret_key.publicKeyBytes(), &key_pair.public_key.toBytes())) {
396399 return error.KeyMismatch;
397400 }
398401 const scalar_and_prefix = key_pair.secret_key.scalarAndPrefix();
399402 var h = Sha512.init(.{});
400403 h.update(&scalar_and_prefix.prefix);
401 var noise2: [noise_length]u8 = undefined;
402 crypto.random.bytes(&noise2);
403 h.update(&noise2);
404 h.update(entropy);
404405 if (noise) |*z| {
405406 h.update(z);
406407 }
......@@ -420,7 +421,7 @@ pub const Ed25519 = struct {
420421 };
421422
422423 /// Verify several signatures in a single operation, much faster than verifying signatures one-by-one
423 pub fn verifyBatch(comptime count: usize, signature_batch: [count]BatchElement) (SignatureVerificationError || IdentityElementError || WeakPublicKeyError || EncodingError || NonCanonicalError)!void {
424 pub fn verifyBatch(io: std.Io, comptime count: usize, signature_batch: [count]BatchElement) (SignatureVerificationError || IdentityElementError || WeakPublicKeyError || EncodingError || NonCanonicalError)!void {
424425 var r_batch: [count]CompressedScalar = undefined;
425426 var s_batch: [count]CompressedScalar = undefined;
426427 var a_batch: [count]Curve = undefined;
......@@ -454,7 +455,7 @@ pub const Ed25519 = struct {
454455
455456 var z_batch: [count]Curve.scalar.CompressedScalar = undefined;
456457 for (&z_batch) |*z| {
457 crypto.random.bytes(z[0..16]);
458 io.random(z[0..16]);
458459 @memset(z[16..], 0);
459460 }
460461
......@@ -587,12 +588,14 @@ test "signature" {
587588}
588589
589590test "batch verification" {
591 const io = std.testing.io;
592
590593 for (0..16) |_| {
591 const key_pair = Ed25519.KeyPair.generate();
594 const key_pair = Ed25519.KeyPair.generate(io);
592595 var msg1: [32]u8 = undefined;
593596 var msg2: [32]u8 = undefined;
594 crypto.random.bytes(&msg1);
595 crypto.random.bytes(&msg2);
597 io.random(&msg1);
598 io.random(&msg2);
596599 const sig1 = try key_pair.sign(&msg1, null);
597600 const sig2 = try key_pair.sign(&msg2, null);
598601 var signature_batch = [_]Ed25519.BatchElement{
......@@ -607,10 +610,10 @@ test "batch verification" {
607610 .public_key = key_pair.public_key,
608611 },
609612 };
610 try Ed25519.verifyBatch(2, signature_batch);
613 try Ed25519.verifyBatch(io, 2, signature_batch);
611614
612615 signature_batch[1].sig = sig1;
613 try std.testing.expectError(error.SignatureVerificationFailed, Ed25519.verifyBatch(signature_batch.len, signature_batch));
616 try std.testing.expectError(error.SignatureVerificationFailed, Ed25519.verifyBatch(io, signature_batch.len, signature_batch));
614617 }
615618}
616619
......@@ -718,14 +721,15 @@ test "test vectors" {
718721}
719722
720723test "with blind keys" {
724 const io = std.testing.io;
721725 const BlindKeyPair = Ed25519.key_blinding.BlindKeyPair;
722726
723727 // Create a standard Ed25519 key pair
724 const kp = Ed25519.KeyPair.generate();
728 const kp = Ed25519.KeyPair.generate(io);
725729
726730 // Create a random blinding seed
727731 var blind: [32]u8 = undefined;
728 crypto.random.bytes(&blind);
732 io.random(&blind);
729733
730734 // Blind the key pair
731735 const blind_kp = try BlindKeyPair.init(kp, blind, "ctx");
......@@ -741,9 +745,12 @@ test "with blind keys" {
741745}
742746
743747test "signatures with streaming" {
744 const kp = Ed25519.KeyPair.generate();
748 const io = std.testing.io;
749 const kp = Ed25519.KeyPair.generate(io);
745750
746 var signer = try kp.signer(null);
751 var entropy: [Ed25519.noise_length]u8 = undefined;
752 io.random(&entropy);
753 var signer = try kp.signer(null, &entropy);
747754 signer.update("mes");
748755 signer.update("sage");
749756 const sig = signer.finalize();
......@@ -757,7 +764,8 @@ test "signatures with streaming" {
757764}
758765
759766test "key pair from secret key" {
760 const kp = Ed25519.KeyPair.generate();
767 const io = std.testing.io;
768 const kp = Ed25519.KeyPair.generate(io);
761769 const kp2 = try Ed25519.KeyPair.fromSecretKey(kp.secret_key);
762770 try std.testing.expectEqualSlices(u8, &kp.secret_key.toBytes(), &kp2.secret_key.toBytes());
763771 try std.testing.expectEqualSlices(u8, &kp.public_key.toBytes(), &kp2.public_key.toBytes());
......@@ -788,7 +796,8 @@ test "cofactored vs cofactorless verification" {
788796}
789797
790798test "regular signature verifies with both verify and verifyStrict" {
791 const kp = Ed25519.KeyPair.generate();
799 const io = std.testing.io;
800 const kp = Ed25519.KeyPair.generate(io);
792801 const msg = "test message";
793802 const sig = try kp.sign(msg, null);
794803 try sig.verify(msg, kp.public_key);
lib/std/crypto/25519/edwards25519.zig+5-3
......@@ -575,10 +575,11 @@ test "packing/unpacking" {
575575}
576576
577577test "point addition/subtraction" {
578 const io = std.testing.io;
578579 var s1: [32]u8 = undefined;
579580 var s2: [32]u8 = undefined;
580 crypto.random.bytes(&s1);
581 crypto.random.bytes(&s2);
581 io.random(&s1);
582 io.random(&s2);
582583 const p = try Edwards25519.basePoint.clampedMul(s1);
583584 const q = try Edwards25519.basePoint.clampedMul(s2);
584585 const r = p.add(q).add(q).sub(q).sub(q);
......@@ -622,9 +623,10 @@ test "implicit reduction of invalid scalars" {
622623}
623624
624625test "subgroup check" {
626 const io = std.testing.io;
625627 for (0..100) |_| {
626628 var p = Edwards25519.basePoint;
627 const s = Edwards25519.scalar.random();
629 const s = Edwards25519.scalar.random(io);
628630 p = try p.mulPublic(s);
629631 try p.rejectUnexpectedSubgroup();
630632 }
lib/std/crypto/25519/scalar.zig+7-6
......@@ -101,8 +101,8 @@ pub fn sub(a: CompressedScalar, b: CompressedScalar) CompressedScalar {
101101}
102102
103103/// Return a random scalar < L
104pub fn random() CompressedScalar {
105 return Scalar.random().toBytes();
104pub fn random(io: std.Io) CompressedScalar {
105 return Scalar.random(io).toBytes();
106106}
107107
108108/// A scalar in unpacked representation
......@@ -560,10 +560,10 @@ pub const Scalar = struct {
560560 }
561561
562562 /// Return a random scalar < L.
563 pub fn random() Scalar {
563 pub fn random(io: std.Io) Scalar {
564564 var s: [64]u8 = undefined;
565565 while (true) {
566 crypto.random.bytes(&s);
566 io.random(&s);
567567 const n = Scalar.fromBytes64(s);
568568 if (!n.isZero()) {
569569 return n;
......@@ -879,8 +879,9 @@ test "scalar field inversion" {
879879}
880880
881881test "random scalar" {
882 const s1 = random();
883 const s2 = random();
882 const io = std.testing.io;
883 const s1 = random(io);
884 const s2 = random(io);
884885 try std.testing.expect(!mem.eql(u8, &s1, &s2));
885886}
886887
lib/std/crypto/25519/x25519.zig+2-2
......@@ -41,10 +41,10 @@ pub const X25519 = struct {
4141 }
4242
4343 /// Generate a new, random key pair.
44 pub fn generate() KeyPair {
44 pub fn generate(io: std.Io) KeyPair {
4545 var random_seed: [seed_length]u8 = undefined;
4646 while (true) {
47 crypto.random.bytes(&random_seed);
47 io.random(&random_seed);
4848 return generateDeterministic(random_seed) catch {
4949 @branchHint(.unlikely);
5050 continue;
lib/std/crypto/argon2.zig+1-1
......@@ -533,7 +533,7 @@ const PhcFormatHasher = struct {
533533 if (params.secret != null or params.ad != null) return HasherError.InvalidEncoding;
534534
535535 var salt: [default_salt_len]u8 = undefined;
536 crypto.random.bytes(&salt);
536 io.random(&salt);
537537
538538 var hash: [default_hash_len]u8 = undefined;
539539 try kdf(allocator, &hash, password, &salt, params, mode, io);
lib/std/crypto/bcrypt.zig+72-39
......@@ -17,7 +17,7 @@ const HasherError = pwhash.HasherError;
1717const EncodingError = phc_format.Error;
1818const Error = pwhash.Error;
1919
20const salt_length: usize = 16;
20pub const salt_length: usize = 16;
2121const salt_str_length: usize = 22;
2222const ct_str_length: usize = 31;
2323const ct_length: usize = 24;
......@@ -426,7 +426,7 @@ pub const Params = struct {
426426
427427fn bcryptWithTruncation(
428428 password: []const u8,
429 salt: [salt_length]u8,
429 salt: *const [salt_length]u8,
430430 params: Params,
431431) [dk_length]u8 {
432432 var state = State{};
......@@ -435,13 +435,13 @@ fn bcryptWithTruncation(
435435 @memcpy(password_buf[0..trimmed_len], password[0..trimmed_len]);
436436 password_buf[trimmed_len] = 0;
437437 const passwordZ = password_buf[0 .. trimmed_len + 1];
438 state.expand(salt[0..], passwordZ);
438 state.expand(salt, passwordZ);
439439
440440 const rounds: u64 = @as(u64, 1) << params.rounds_log;
441441 var k: u64 = 0;
442442 while (k < rounds) : (k += 1) {
443443 state.expand0(passwordZ);
444 state.expand0(salt[0..]);
444 state.expand0(salt);
445445 }
446446 crypto.secureZero(u8, &password_buf);
447447
......@@ -467,7 +467,7 @@ fn bcryptWithTruncation(
467467/// For key derivation, use `bcrypt.pbkdf()` or `bcrypt.opensshKdf()` instead.
468468pub fn bcrypt(
469469 password: []const u8,
470 salt: [salt_length]u8,
470 salt: *const [salt_length]u8,
471471 params: Params,
472472) [dk_length]u8 {
473473 if (password.len <= 72 or params.silently_truncate_password) {
......@@ -475,7 +475,7 @@ pub fn bcrypt(
475475 }
476476
477477 var pre_hash: [HmacSha512.mac_length]u8 = undefined;
478 HmacSha512.create(&pre_hash, password, &salt);
478 HmacSha512.create(&pre_hash, password, salt);
479479
480480 const Encoder = crypt_format.Codec.Encoder;
481481 var pre_hash_b64: [Encoder.calcSize(pre_hash.len)]u8 = undefined;
......@@ -623,16 +623,16 @@ const crypt_format = struct {
623623
624624 fn strHashInternal(
625625 password: []const u8,
626 salt: [salt_length]u8,
626 salt: *const [salt_length]u8,
627627 params: Params,
628628 ) [hash_length]u8 {
629629 var dk = bcrypt(password, salt, params);
630630
631631 var salt_str: [salt_str_length]u8 = undefined;
632 _ = Codec.Encoder.encode(salt_str[0..], salt[0..]);
632 _ = Codec.Encoder.encode(&salt_str, salt);
633633
634634 var ct_str: [ct_str_length]u8 = undefined;
635 _ = Codec.Encoder.encode(ct_str[0..], dk[0..]);
635 _ = Codec.Encoder.encode(&ct_str, dk[0..]);
636636
637637 var s_buf: [hash_length]u8 = undefined;
638638 const s = fmt.bufPrint(
......@@ -657,21 +657,20 @@ const PhcFormatHasher = struct {
657657 hash: BinValue(dk_length),
658658 };
659659
660 /// Return a non-deterministic hash of the password encoded as a PHC-format string
660 /// Return a non-deterministic hash of the password encoded as a PHC-format string.
661661 fn create(
662662 password: []const u8,
663663 params: Params,
664664 buf: []u8,
665 /// Filled with cryptographically secure entropy.
666 salt: *const [salt_length]u8,
665667 ) HasherError![]const u8 {
666 var salt: [salt_length]u8 = undefined;
667 crypto.random.bytes(&salt);
668
669668 const hash = bcrypt(password, salt, params);
670669
671670 return phc_format.serialize(HashResult{
672671 .alg_id = alg_id,
673672 .r = params.rounds_log,
674 .salt = try BinValue(salt_length).fromSlice(&salt),
673 .salt = try BinValue(salt_length).fromSlice(salt),
675674 .hash = try BinValue(dk_length).fromSlice(&hash),
676675 }, buf);
677676 }
......@@ -688,11 +687,11 @@ const PhcFormatHasher = struct {
688687 if (hash_result.salt.len != salt_length or hash_result.hash.len != dk_length)
689688 return HasherError.InvalidEncoding;
690689
691 const params = Params{
690 const params: Params = .{
692691 .rounds_log = hash_result.r,
693692 .silently_truncate_password = silently_truncate_password,
694693 };
695 const hash = bcrypt(password, hash_result.salt.buf, params);
694 const hash = bcrypt(password, &hash_result.salt.buf, params);
696695 const expected_hash = hash_result.hash.constSlice();
697696
698697 if (!mem.eql(u8, &hash, expected_hash)) return HasherError.PasswordVerificationFailed;
......@@ -709,12 +708,11 @@ const CryptFormatHasher = struct {
709708 password: []const u8,
710709 params: Params,
711710 buf: []u8,
711 /// Filled with cryptographically secure entropy.
712 salt: *const [salt_length]u8,
712713 ) HasherError![]const u8 {
713714 if (buf.len < pwhash_str_length) return HasherError.NoSpaceLeft;
714715
715 var salt: [salt_length]u8 = undefined;
716 crypto.random.bytes(&salt);
717
718716 const hash = crypt_format.strHashInternal(password, salt, params);
719717 @memcpy(buf[0..hash.len], &hash);
720718
......@@ -736,9 +734,9 @@ const CryptFormatHasher = struct {
736734
737735 const salt_str = str[7..][0..salt_str_length];
738736 var salt: [salt_length]u8 = undefined;
739 crypt_format.Codec.Decoder.decode(salt[0..], salt_str[0..]) catch return HasherError.InvalidEncoding;
737 crypt_format.Codec.Decoder.decode(&salt, salt_str) catch return HasherError.InvalidEncoding;
740738
741 const wanted_s = crypt_format.strHashInternal(password, salt, .{
739 const wanted_s = crypt_format.strHashInternal(password, &salt, .{
742740 .rounds_log = rounds_log,
743741 .silently_truncate_password = silently_truncate_password,
744742 });
......@@ -756,21 +754,28 @@ pub const HashOptions = struct {
756754 encoding: pwhash.Encoding,
757755};
758756
759/// Compute a hash of a password using 2^rounds_log rounds of the bcrypt key stretching function.
760/// bcrypt is a computationally expensive and cache-hard function, explicitly designed to slow down exhaustive searches.
757/// Compute a hash of a password using 2^rounds_log rounds of the bcrypt key
758/// stretching function.
759///
760/// bcrypt is a computationally expensive and cache-hard function, explicitly
761/// designed to slow down exhaustive searches.
761762///
762/// The function returns a string that includes all the parameters required for verification.
763/// The function returns a string that includes all the parameters required for
764/// verification.
763765///
764/// IMPORTANT: by design, bcrypt silently truncates passwords to 72 bytes.
765/// If this is an issue for your application, set the `silently_truncate_password` option to `false`.
766/// By design, bcrypt silently truncates passwords to 72 bytes. If this is an
767/// issue for your application, set the `silently_truncate_password` option to
768/// `false`.
766769pub fn strHash(
767770 password: []const u8,
768771 options: HashOptions,
769772 out: []u8,
773 /// Filled with cryptographically secure entropy.
774 salt: *const [salt_length]u8,
770775) Error![]const u8 {
771776 switch (options.encoding) {
772 .phc => return PhcFormatHasher.create(password, options.params, out),
773 .crypt => return CryptFormatHasher.create(password, options.params, out),
777 .phc => return PhcFormatHasher.create(password, options.params, out, salt),
778 .crypt => return CryptFormatHasher.create(password, options.params, out, salt),
774779 }
775780}
776781
......@@ -796,8 +801,9 @@ pub fn strVerify(
796801}
797802
798803test "bcrypt codec" {
804 const io = testing.io;
799805 var salt: [salt_length]u8 = undefined;
800 crypto.random.bytes(&salt);
806 io.random(&salt);
801807 var salt_str: [salt_str_length]u8 = undefined;
802808 _ = crypt_format.Codec.Encoder.encode(salt_str[0..], salt[0..]);
803809 var salt2: [salt_length]u8 = undefined;
......@@ -806,14 +812,20 @@ test "bcrypt codec" {
806812}
807813
808814test "bcrypt crypt format" {
809 var hash_options = HashOptions{
815 const io = testing.io;
816
817 var hash_options: HashOptions = .{
810818 .params = .{ .rounds_log = 5, .silently_truncate_password = false },
811819 .encoding = .crypt,
812820 };
813 var verify_options = VerifyOptions{ .silently_truncate_password = false };
821 var verify_options: VerifyOptions = .{ .silently_truncate_password = false };
814822
815823 var buf: [hash_length]u8 = undefined;
816 const s = try strHash("password", hash_options, &buf);
824 const s = s: {
825 var salt: [salt_length]u8 = undefined;
826 io.random(&salt);
827 break :s try strHash("password", hash_options, &buf, &salt);
828 };
817829
818830 try testing.expect(mem.startsWith(u8, s, crypt_format.prefix));
819831 try strVerify(s, "password", verify_options);
......@@ -823,7 +835,11 @@ test "bcrypt crypt format" {
823835 );
824836
825837 var long_buf: [hash_length]u8 = undefined;
826 var long_s = try strHash("password" ** 100, hash_options, &long_buf);
838 var long_s = s: {
839 var salt: [salt_length]u8 = undefined;
840 io.random(&salt);
841 break :s try strHash("password" ** 100, hash_options, &long_buf, &salt);
842 };
827843
828844 try testing.expect(mem.startsWith(u8, long_s, crypt_format.prefix));
829845 try strVerify(long_s, "password" ** 100, verify_options);
......@@ -834,7 +850,11 @@ test "bcrypt crypt format" {
834850
835851 hash_options.params.silently_truncate_password = true;
836852 verify_options.silently_truncate_password = true;
837 long_s = try strHash("password" ** 100, hash_options, &long_buf);
853 long_s = s: {
854 var salt: [salt_length]u8 = undefined;
855 io.random(&salt);
856 break :s try strHash("password" ** 100, hash_options, &long_buf, &salt);
857 };
838858 try strVerify(long_s, "password" ** 101, verify_options);
839859
840860 try strVerify(
......@@ -845,15 +865,20 @@ test "bcrypt crypt format" {
845865}
846866
847867test "bcrypt phc format" {
848 var hash_options = HashOptions{
868 const io = testing.io;
869 var hash_options: HashOptions = .{
849870 .params = .{ .rounds_log = 5, .silently_truncate_password = false },
850871 .encoding = .phc,
851872 };
852 var verify_options = VerifyOptions{ .silently_truncate_password = false };
873 var verify_options: VerifyOptions = .{ .silently_truncate_password = false };
853874 const prefix = "$bcrypt$";
854875
855876 var buf: [hash_length * 2]u8 = undefined;
856 const s = try strHash("password", hash_options, &buf);
877 const s = s: {
878 var salt: [salt_length]u8 = undefined;
879 io.random(&salt);
880 break :s try strHash("password", hash_options, &buf, &salt);
881 };
857882
858883 try testing.expect(mem.startsWith(u8, s, prefix));
859884 try strVerify(s, "password", verify_options);
......@@ -863,7 +888,11 @@ test "bcrypt phc format" {
863888 );
864889
865890 var long_buf: [hash_length * 2]u8 = undefined;
866 var long_s = try strHash("password" ** 100, hash_options, &long_buf);
891 var long_s = s: {
892 var salt: [salt_length]u8 = undefined;
893 io.random(&salt);
894 break :s try strHash("password" ** 100, hash_options, &long_buf, &salt);
895 };
867896
868897 try testing.expect(mem.startsWith(u8, long_s, prefix));
869898 try strVerify(long_s, "password" ** 100, verify_options);
......@@ -874,7 +903,11 @@ test "bcrypt phc format" {
874903
875904 hash_options.params.silently_truncate_password = true;
876905 verify_options.silently_truncate_password = true;
877 long_s = try strHash("password" ** 100, hash_options, &long_buf);
906 long_s = s: {
907 var salt: [salt_length]u8 = undefined;
908 io.random(&salt);
909 break :s try strHash("password" ** 100, hash_options, &long_buf, &salt);
910 };
878911 try strVerify(long_s, "password" ** 101, verify_options);
879912
880913 try strVerify(
lib/std/crypto/ecdsa.zig+17-11
......@@ -323,10 +323,10 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {
323323 }
324324
325325 /// Generate a new, random key pair.
326 pub fn generate() KeyPair {
326 pub fn generate(io: std.Io) KeyPair {
327327 var random_seed: [seed_length]u8 = undefined;
328328 while (true) {
329 crypto.random.bytes(&random_seed);
329 io.random(&random_seed);
330330 return generateDeterministic(random_seed) catch {
331331 @branchHint(.unlikely);
332332 continue;
......@@ -417,12 +417,13 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {
417417test "Basic operations over EcdsaP384Sha384" {
418418 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
419419
420 const io = testing.io;
420421 const Scheme = EcdsaP384Sha384;
421 const kp = Scheme.KeyPair.generate();
422 const kp = Scheme.KeyPair.generate(io);
422423 const msg = "test";
423424
424425 var noise: [Scheme.noise_length]u8 = undefined;
425 crypto.random.bytes(&noise);
426 io.random(&noise);
426427 const sig = try kp.sign(msg, noise);
427428 try sig.verify(msg, kp.public_key);
428429
......@@ -433,12 +434,13 @@ test "Basic operations over EcdsaP384Sha384" {
433434test "Basic operations over Secp256k1" {
434435 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
435436
437 const io = testing.io;
436438 const Scheme = EcdsaSecp256k1Sha256oSha256;
437 const kp = Scheme.KeyPair.generate();
439 const kp = Scheme.KeyPair.generate(io);
438440 const msg = "test";
439441
440442 var noise: [Scheme.noise_length]u8 = undefined;
441 crypto.random.bytes(&noise);
443 io.random(&noise);
442444 const sig = try kp.sign(msg, noise);
443445 try sig.verify(msg, kp.public_key);
444446
......@@ -449,12 +451,13 @@ test "Basic operations over Secp256k1" {
449451test "Basic operations over EcdsaP384Sha256" {
450452 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
451453
454 const io = testing.io;
452455 const Scheme = Ecdsa(crypto.ecc.P384, crypto.hash.sha2.Sha256);
453 const kp = Scheme.KeyPair.generate();
456 const kp = Scheme.KeyPair.generate(io);
454457 const msg = "test";
455458
456459 var noise: [Scheme.noise_length]u8 = undefined;
457 crypto.random.bytes(&noise);
460 io.random(&noise);
458461 const sig = try kp.sign(msg, noise);
459462 try sig.verify(msg, kp.public_key);
460463
......@@ -502,8 +505,10 @@ test "Verifying a existing signature with EcdsaP384Sha256" {
502505test "Prehashed message operations" {
503506 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
504507
508 const io = testing.io;
509
505510 const Scheme = EcdsaP256Sha256;
506 const kp = Scheme.KeyPair.generate();
511 const kp = Scheme.KeyPair.generate(io);
507512 const msg = "test message for prehashed signing";
508513
509514 const Hash = crypto.hash.sha2.Sha256;
......@@ -518,7 +523,7 @@ test "Prehashed message operations" {
518523 try testing.expectError(error.SignatureVerificationFailed, sig.verifyPrehashed(bad_hash, kp.public_key));
519524
520525 var noise: [Scheme.noise_length]u8 = undefined;
521 crypto.random.bytes(&noise);
526 io.random(&noise);
522527 const sig_with_noise = try kp.signPrehashed(msg_hash, noise);
523528 try sig_with_noise.verifyPrehashed(msg_hash, kp.public_key);
524529
......@@ -1628,8 +1633,9 @@ fn tvTry(comptime Scheme: type, vector: TestVector) !void {
16281633test "Sec1 encoding/decoding" {
16291634 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
16301635
1636 const io = testing.io;
16311637 const Scheme = EcdsaP384Sha384;
1632 const kp = Scheme.KeyPair.generate();
1638 const kp = Scheme.KeyPair.generate(io);
16331639 const pk = kp.public_key;
16341640 const pk_compressed_sec1 = pk.toCompressedSec1();
16351641 const pk_recovered1 = try Scheme.PublicKey.fromSec1(&pk_compressed_sec1);
lib/std/crypto/hybrid_kem.zig+74-61
......@@ -174,43 +174,56 @@ pub fn HybridKem(comptime params: Params) type {
174174 return .{ .bytes = buf.* };
175175 }
176176
177 /// Generates a shared secret and encapsulates it for the public key.
178 /// If `seed` is `null`, uses random bytes from `std.crypto.random`.
179 /// If `seed` is set, encapsulation is deterministic (for testing only).
180 pub fn encaps(self: PublicKey, seed: ?[]const u8) !EncapsulatedSecret {
181 const pq_nek = params.PqKem.PublicKey.encoded_length;
182 const ek_pq = try params.PqKem.PublicKey.fromBytes(self.bytes[0..pq_nek]);
183 const ek_t = self.bytes[pq_nek..][0..params.Group.element_length];
184
177 /// Generates a shared secret, encapsulated for the public key,
178 /// using random bytes.
179 ///
180 /// This is recommended over `encapsDeterministic`.
181 pub fn encaps(pk: PublicKey, io: std.Io) !EncapsulatedSecret {
185182 var seed_pq: [32]u8 = undefined;
186 var seed_t_expanded: [params.Group.seed_length]u8 = undefined;
183 io.random(&seed_pq);
184 var seed_t: [32]u8 = undefined;
185 io.random(&seed_t);
186 var seed_t_expanded: [params.Group.seed_length]u8 = try expandRandomnessSeed(seed_t);
187 return encapsInner(pk, &seed_pq, &seed_t_expanded);
188 }
187189
188 if (seed) |r| {
189 if (r.len < 32) return error.InsufficientRandomness;
190 seed_pq = r[0..32].*;
190 /// Generates a shared secret, encapsulated for the public key,
191 /// using the provided seed.
192 ///
193 /// Calling `encaps` instead is recommended.
194 pub fn encapsDeterministic(pk: PublicKey, seed: []const u8) !EncapsulatedSecret {
195 if (seed.len < 32) return error.InsufficientRandomness;
196 var seed_pq: [32]u8 = seed[0..32].*;
197 var seed_t_expanded: [params.Group.seed_length]u8 = undefined;
191198
192 const t_randomness = r[32..];
199 const t_randomness = seed[32..];
200 if (t_randomness.len < params.Group.seed_length) {
201 // Provided randomness is shorter than seed_length, use it directly
202 // (test vectors provide just enough for randomScalar)
203 @memcpy(seed_t_expanded[0..t_randomness.len], t_randomness);
204 // Pad the rest with zeros if needed (shouldn't be used by randomScalar)
193205 if (t_randomness.len < params.Group.seed_length) {
194 // Provided randomness is shorter than seed_length, use it directly
195 // (test vectors provide just enough for randomScalar)
196 @memcpy(seed_t_expanded[0..t_randomness.len], t_randomness);
197 // Pad the rest with zeros if needed (shouldn't be used by randomScalar)
198 if (t_randomness.len < params.Group.seed_length) {
199 @memset(seed_t_expanded[t_randomness.len..], 0);
200 }
201 } else {
202 // Full randomness provided
203 @memcpy(&seed_t_expanded, t_randomness[0..params.Group.seed_length]);
206 @memset(seed_t_expanded[t_randomness.len..], 0);
204207 }
205208 } else {
206 crypto.random.bytes(&seed_pq);
207 var seed_t: [32]u8 = undefined;
208 crypto.random.bytes(&seed_t);
209 seed_t_expanded = try expandRandomnessSeed(seed_t);
209 // Full randomness provided
210 @memcpy(&seed_t_expanded, t_randomness[0..params.Group.seed_length]);
210211 }
211212
212 const pq_encap = ek_pq.encaps(seed_pq);
213 const sk_e = try params.Group.randomScalar(&seed_t_expanded);
213 return encapsInner(pk, &seed_pq, &seed_t_expanded);
214 }
215
216 fn encapsInner(
217 pk: PublicKey,
218 seed_pq: *[32]u8,
219 seed_t_expanded: *[params.Group.seed_length]u8,
220 ) !EncapsulatedSecret {
221 const pq_nek = params.PqKem.PublicKey.encoded_length;
222 const ek_pq = try params.PqKem.PublicKey.fromBytes(pk.bytes[0..pq_nek]);
223 const ek_t = pk.bytes[pq_nek..][0..params.Group.element_length];
224
225 const pq_encap = ek_pq.encapsDeterministic(seed_pq);
226 const sk_e = try params.Group.randomScalar(seed_t_expanded);
214227 const ct_t_point = try params.Group.mulBase(sk_e);
215228 const ct_t = if (is_nist_curve) params.Group.encodePoint(ct_t_point) else ct_t_point;
216229
......@@ -280,9 +293,9 @@ pub fn HybridKem(comptime params: Params) type {
280293 }
281294
282295 /// Generates a new random key pair.
283 pub fn generate() !KeyPair {
296 pub fn generate(io: std.Io) !KeyPair {
284297 var seed: [params.Nseed]u8 = undefined;
285 crypto.random.bytes(&seed);
298 io.random(&seed);
286299 return generateDeterministic(seed);
287300 }
288301 };
......@@ -386,7 +399,7 @@ test "MLKEM768-X25519 basic round trip" {
386399 var enc_seed: [64]u8 = undefined;
387400 @memset(&enc_seed, 0x43);
388401
389 const encap_result = try kp.public_key.encaps(&enc_seed);
402 const encap_result = try kp.public_key.encapsDeterministic(&enc_seed);
390403 const ss_decap = try kp.secret_key.decaps(&encap_result.ciphertext);
391404
392405 try testing.expectEqualSlices(u8, &encap_result.shared_secret, &ss_decap);
......@@ -408,7 +421,7 @@ test "MLKEM768-X25519 test vector 0" {
408421 const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed);
409422 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
410423
411 const enc_result = try kp.public_key.encaps(&randomness);
424 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
412425 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
413426 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
414427
......@@ -432,7 +445,7 @@ test "MLKEM768-X25519 test vector 1" {
432445 const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed);
433446 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
434447
435 const enc_result = try kp.public_key.encaps(&randomness);
448 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
436449 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
437450 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
438451
......@@ -456,7 +469,7 @@ test "MLKEM768-X25519 test vector 2" {
456469 const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed);
457470 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
458471
459 const enc_result = try kp.public_key.encaps(&randomness);
472 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
460473 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
461474 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
462475
......@@ -480,7 +493,7 @@ test "MLKEM768-X25519 test vector 3" {
480493 const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed);
481494 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
482495
483 const enc_result = try kp.public_key.encaps(&randomness);
496 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
484497 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
485498 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
486499
......@@ -504,7 +517,7 @@ test "MLKEM768-X25519 test vector 4" {
504517 const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed);
505518 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
506519
507 const enc_result = try kp.public_key.encaps(&randomness);
520 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
508521 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
509522 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
510523
......@@ -528,7 +541,7 @@ test "MLKEM768-X25519 test vector 5" {
528541 const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed);
529542 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
530543
531 const enc_result = try kp.public_key.encaps(&randomness);
544 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
532545 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
533546 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
534547
......@@ -552,7 +565,7 @@ test "MLKEM768-X25519 test vector 6" {
552565 const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed);
553566 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
554567
555 const enc_result = try kp.public_key.encaps(&randomness);
568 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
556569 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
557570 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
558571
......@@ -576,7 +589,7 @@ test "MLKEM768-X25519 test vector 7" {
576589 const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed);
577590 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
578591
579 const enc_result = try kp.public_key.encaps(&randomness);
592 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
580593 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
581594 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
582595
......@@ -600,7 +613,7 @@ test "MLKEM768-X25519 test vector 8" {
600613 const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed);
601614 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
602615
603 const enc_result = try kp.public_key.encaps(&randomness);
616 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
604617 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
605618 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
606619
......@@ -624,7 +637,7 @@ test "MLKEM768-X25519 test vector 9" {
624637 const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed);
625638 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
626639
627 const enc_result = try kp.public_key.encaps(&randomness);
640 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
628641 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
629642 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
630643
......@@ -648,7 +661,7 @@ test "MLKEM768-P256 test vector 0" {
648661 const kp = try MlKem768P256.KeyPair.generateDeterministic(seed);
649662 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
650663
651 const enc_result = try kp.public_key.encaps(&randomness);
664 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
652665 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
653666 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
654667
......@@ -672,7 +685,7 @@ test "MLKEM768-P256 test vector 1" {
672685 const kp = try MlKem768P256.KeyPair.generateDeterministic(seed);
673686 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
674687
675 const enc_result = try kp.public_key.encaps(&randomness);
688 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
676689 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
677690 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
678691
......@@ -696,7 +709,7 @@ test "MLKEM768-P256 test vector 2" {
696709 const kp = try MlKem768P256.KeyPair.generateDeterministic(seed);
697710 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
698711
699 const enc_result = try kp.public_key.encaps(&randomness);
712 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
700713 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
701714 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
702715
......@@ -720,7 +733,7 @@ test "MLKEM768-P256 test vector 3" {
720733 const kp = try MlKem768P256.KeyPair.generateDeterministic(seed);
721734 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
722735
723 const enc_result = try kp.public_key.encaps(&randomness);
736 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
724737 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
725738 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
726739
......@@ -744,7 +757,7 @@ test "MLKEM768-P256 test vector 4" {
744757 const kp = try MlKem768P256.KeyPair.generateDeterministic(seed);
745758 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
746759
747 const enc_result = try kp.public_key.encaps(&randomness);
760 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
748761 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
749762 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
750763
......@@ -768,7 +781,7 @@ test "MLKEM768-P256 test vector 5" {
768781 const kp = try MlKem768P256.KeyPair.generateDeterministic(seed);
769782 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
770783
771 const enc_result = try kp.public_key.encaps(&randomness);
784 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
772785 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
773786 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
774787
......@@ -792,7 +805,7 @@ test "MLKEM768-P256 test vector 6" {
792805 const kp = try MlKem768P256.KeyPair.generateDeterministic(seed);
793806 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
794807
795 const enc_result = try kp.public_key.encaps(&randomness);
808 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
796809 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
797810 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
798811
......@@ -816,7 +829,7 @@ test "MLKEM768-P256 test vector 7" {
816829 const kp = try MlKem768P256.KeyPair.generateDeterministic(seed);
817830 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
818831
819 const enc_result = try kp.public_key.encaps(&randomness);
832 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
820833 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
821834 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
822835
......@@ -840,7 +853,7 @@ test "MLKEM768-P256 test vector 8" {
840853 const kp = try MlKem768P256.KeyPair.generateDeterministic(seed);
841854 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
842855
843 const enc_result = try kp.public_key.encaps(&randomness);
856 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
844857 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
845858 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
846859
......@@ -864,7 +877,7 @@ test "MLKEM768-P256 test vector 9" {
864877 const kp = try MlKem768P256.KeyPair.generateDeterministic(seed);
865878 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
866879
867 const enc_result = try kp.public_key.encaps(&randomness);
880 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
868881 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
869882 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
870883
......@@ -888,7 +901,7 @@ test "MLKEM1024-P384 test vector 0" {
888901 const kp = try MlKem1024P384.KeyPair.generateDeterministic(seed);
889902 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
890903
891 const enc_result = try kp.public_key.encaps(&randomness);
904 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
892905 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
893906 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
894907
......@@ -912,7 +925,7 @@ test "MLKEM1024-P384 test vector 1" {
912925 const kp = try MlKem1024P384.KeyPair.generateDeterministic(seed);
913926 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
914927
915 const enc_result = try kp.public_key.encaps(&randomness);
928 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
916929 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
917930 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
918931
......@@ -936,7 +949,7 @@ test "MLKEM1024-P384 test vector 2" {
936949 const kp = try MlKem1024P384.KeyPair.generateDeterministic(seed);
937950 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
938951
939 const enc_result = try kp.public_key.encaps(&randomness);
952 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
940953 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
941954 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
942955
......@@ -960,7 +973,7 @@ test "MLKEM1024-P384 test vector 3" {
960973 const kp = try MlKem1024P384.KeyPair.generateDeterministic(seed);
961974 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
962975
963 const enc_result = try kp.public_key.encaps(&randomness);
976 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
964977 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
965978 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
966979
......@@ -984,7 +997,7 @@ test "MLKEM1024-P384 test vector 4" {
984997 const kp = try MlKem1024P384.KeyPair.generateDeterministic(seed);
985998 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
986999
987 const enc_result = try kp.public_key.encaps(&randomness);
1000 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
9881001 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
9891002 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
9901003
......@@ -1008,7 +1021,7 @@ test "MLKEM1024-P384 test vector 5" {
10081021 const kp = try MlKem1024P384.KeyPair.generateDeterministic(seed);
10091022 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
10101023
1011 const enc_result = try kp.public_key.encaps(&randomness);
1024 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
10121025 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
10131026 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
10141027
......@@ -1032,7 +1045,7 @@ test "MLKEM1024-P384 test vector 6" {
10321045 const kp = try MlKem1024P384.KeyPair.generateDeterministic(seed);
10331046 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
10341047
1035 const enc_result = try kp.public_key.encaps(&randomness);
1048 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
10361049 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
10371050 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
10381051
......@@ -1056,7 +1069,7 @@ test "MLKEM1024-P384 test vector 7" {
10561069 const kp = try MlKem1024P384.KeyPair.generateDeterministic(seed);
10571070 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
10581071
1059 const enc_result = try kp.public_key.encaps(&randomness);
1072 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
10601073 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
10611074 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
10621075
......@@ -1080,7 +1093,7 @@ test "MLKEM1024-P384 test vector 8" {
10801093 const kp = try MlKem1024P384.KeyPair.generateDeterministic(seed);
10811094 try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes());
10821095
1083 const enc_result = try kp.public_key.encaps(&randomness);
1096 const enc_result = try kp.public_key.encapsDeterministic(&randomness);
10841097 try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext);
10851098 try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret);
10861099
lib/std/crypto/ml_dsa.zig+10-9
......@@ -2019,12 +2019,9 @@ fn MLDSAImpl(comptime p: Params) type {
20192019 secret_key: SecretKey,
20202020
20212021 /// Generate a new random key pair.
2022 /// This uses the system's cryptographically secure random number generator.
2023 ///
2024 /// `crypto.random.bytes` must be supported by the target.
2025 pub fn generate() KeyPair {
2022 pub fn generate(io: std.Io) KeyPair {
20262023 var seed: [Self.seed_length]u8 = undefined;
2027 crypto.random.bytes(&seed);
2024 io.random(&seed);
20282025 return generateDeterministic(seed) catch unreachable;
20292026 }
20302027
......@@ -3198,8 +3195,9 @@ test "ML-DSA-87 KAT test vector 0" {
31983195}
31993196
32003197test "KeyPair API - generate and sign" {
3198 const io = std.testing.io;
32013199 // Test the new KeyPair API with random generation
3202 const kp = MLDSA44.KeyPair.generate();
3200 const kp = MLDSA44.KeyPair.generate(io);
32033201 const msg = "Test message for KeyPair API";
32043202
32053203 // Sign with deterministic mode (no noise)
......@@ -3222,8 +3220,9 @@ test "KeyPair API - generateDeterministic" {
32223220}
32233221
32243222test "KeyPair API - fromSecretKey" {
3223 const io = std.testing.io;
32253224 // Generate a key pair
3226 const kp1 = MLDSA44.KeyPair.generate();
3225 const kp1 = MLDSA44.KeyPair.generate(io);
32273226
32283227 // Derive public key from secret key
32293228 const kp2 = try MLDSA44.KeyPair.fromSecretKey(kp1.secret_key);
......@@ -3235,8 +3234,9 @@ test "KeyPair API - fromSecretKey" {
32353234}
32363235
32373236test "Signature verification with noise" {
3237 const io = std.testing.io;
32383238 // Test signing with randomness (hedged signatures)
3239 const kp = MLDSA65.KeyPair.generate();
3239 const kp = MLDSA65.KeyPair.generate(io);
32403240 const msg = "Message to be signed with randomness";
32413241
32423242 // Create some noise
......@@ -3250,8 +3250,9 @@ test "Signature verification with noise" {
32503250}
32513251
32523252test "Signature verification failure" {
3253 const io = std.testing.io;
32533254 // Test that invalid signatures are rejected
3254 const kp = MLDSA44.KeyPair.generate();
3255 const kp = MLDSA44.KeyPair.generate(io);
32553256 const msg = "Original message";
32563257 const sig = try kp.sign(msg, null);
32573258
lib/std/crypto/ml_kem.zig+29-20
......@@ -244,32 +244,41 @@ fn Kyber(comptime p: Params) type {
244244 /// Size of a serialized representation of the key, in bytes.
245245 pub const encoded_length = InnerPk.encoded_length;
246246
247 /// Generates a shared secret, and encapsulates it for the public key.
248 /// If `seed` is `null`, a random seed is used. This is recommended.
249 /// If `seed` is set, encapsulation is deterministic.
250 pub fn encaps(pk: PublicKey, seed_: ?[encaps_seed_length]u8) EncapsulatedSecret {
247 /// Generates a shared secret, encapsulated for the public key,
248 /// using random bytes.
249 ///
250 /// This is recommended over `encapsDeterministic`.
251 pub fn encaps(pk: PublicKey, io: std.Io) EncapsulatedSecret {
251252 var m: [inner_plaintext_length]u8 = undefined;
253 io.random(&m);
254 return encapsInner(pk, &m);
255 }
252256
253 if (seed_) |seed| {
254 if (p.ml_kem) {
255 @memcpy(&m, &seed);
256 } else {
257 // m = H(seed)
258 sha3.Sha3_256.hash(&seed, &m, .{});
259 }
257 /// Generates a shared secret, encapsulated for the public key,
258 /// using the provided seed.
259 ///
260 /// Calling `encaps` instead is recommended.
261 pub fn encapsDeterministic(pk: PublicKey, seed: *const [encaps_seed_length]u8) EncapsulatedSecret {
262 var m: [inner_plaintext_length]u8 = undefined;
263 if (p.ml_kem) {
264 @memcpy(&m, seed);
260265 } else {
261 crypto.random.bytes(&m);
266 // m = H(seed)
267 sha3.Sha3_256.hash(seed, &m, .{});
262268 }
269 return encapsInner(pk, &m);
270 }
263271
272 fn encapsInner(pk: PublicKey, m: *[inner_plaintext_length]u8) EncapsulatedSecret {
264273 // (K', r) = G(m ‖ H(pk))
265274 var kr: [inner_plaintext_length + h_length]u8 = undefined;
266275 var g = sha3.Sha3_512.init(.{});
267 g.update(&m);
276 g.update(m);
268277 g.update(&pk.hpk);
269278 g.final(&kr);
270279
271280 // c = innerEncrypt(pk, m, r)
272 const ct = pk.pk.encrypt(&m, kr[32..64]);
281 const ct = pk.pk.encrypt(m, kr[32..64]);
273282
274283 if (p.ml_kem) {
275284 return EncapsulatedSecret{
......@@ -398,10 +407,10 @@ fn Kyber(comptime p: Params) type {
398407 }
399408
400409 /// Generate a new, random key pair.
401 pub fn generate() KeyPair {
410 pub fn generate(io: std.Io) KeyPair {
402411 var random_seed: [seed_length]u8 = undefined;
403412 while (true) {
404 crypto.random.bytes(&random_seed);
413 io.random(&random_seed);
405414 return generateDeterministic(random_seed) catch {
406415 @branchHint(.unlikely);
407416 continue;
......@@ -1634,15 +1643,15 @@ test "Test happy flow" {
16341643 }
16351644 inline for (modes) |mode| {
16361645 for (0..10) |i| {
1637 seed[0] = @as(u8, @intCast(i));
1646 seed[0] = @intCast(i);
16381647 const kp = try mode.KeyPair.generateDeterministic(seed);
16391648 const sk = try mode.SecretKey.fromBytes(&kp.secret_key.toBytes());
16401649 try testing.expectEqual(sk, kp.secret_key);
16411650 const pk = try mode.PublicKey.fromBytes(&kp.public_key.toBytes());
16421651 try testing.expectEqual(pk, kp.public_key);
16431652 for (0..10) |j| {
1644 seed[1] = @as(u8, @intCast(j));
1645 const e = pk.encaps(seed[0..32].*);
1653 seed[1] = @intCast(j);
1654 const e = pk.encapsDeterministic(seed[0..32]);
16461655 try testing.expectEqual(e.shared_secret, try sk.decaps(&e.ciphertext));
16471656 }
16481657 }
......@@ -1695,7 +1704,7 @@ fn testNistKat(mode: type, hash: []const u8) !void {
16951704 g2.fill(kseed[32..64]);
16961705 g2.fill(&eseed);
16971706 const kp = try mode.KeyPair.generateDeterministic(kseed);
1698 const e = kp.public_key.encaps(eseed);
1707 const e = kp.public_key.encapsDeterministic(&eseed);
16991708 const ss2 = try kp.secret_key.decaps(&e.ciphertext);
17001709 try testing.expectEqual(ss2, e.shared_secret);
17011710 try fw.writer.print("pk = {X}\n", .{&kp.public_key.toBytes()});
lib/std/crypto/pcurves/p256.zig+2-2
......@@ -122,8 +122,8 @@ pub const P256 = struct {
122122 }
123123
124124 /// Return a random point.
125 pub fn random() P256 {
126 const n = scalar.random(.little);
125 pub fn random(io: std.Io) P256 {
126 const n = scalar.random(io, .little);
127127 return basePoint.mul(n, .little) catch unreachable;
128128 }
129129
lib/std/crypto/pcurves/p256/scalar.zig+4-4
......@@ -68,8 +68,8 @@ pub fn sub(a: CompressedScalar, b: CompressedScalar, endian: std.builtin.Endian)
6868}
6969
7070/// Return a random scalar
71pub fn random(endian: std.builtin.Endian) CompressedScalar {
72 return Scalar.random().toBytes(endian);
71pub fn random(io: std.Io, endian: std.builtin.Endian) CompressedScalar {
72 return Scalar.random(io).toBytes(endian);
7373}
7474
7575/// A scalar in unpacked representation.
......@@ -170,10 +170,10 @@ pub const Scalar = struct {
170170 }
171171
172172 /// Return a random scalar < L.
173 pub fn random() Scalar {
173 pub fn random(io: std.Io) Scalar {
174174 var s: [48]u8 = undefined;
175175 while (true) {
176 crypto.random.bytes(&s);
176 io.random(&s);
177177 const n = Scalar.fromBytes48(s, .little);
178178 if (!n.isZero()) {
179179 return n;
lib/std/crypto/pcurves/p384.zig+2-2
......@@ -122,8 +122,8 @@ pub const P384 = struct {
122122 }
123123
124124 /// Return a random point.
125 pub fn random() P384 {
126 const n = scalar.random(.little);
125 pub fn random(io: std.Io) P384 {
126 const n = scalar.random(io, .little);
127127 return basePoint.mul(n, .little) catch unreachable;
128128 }
129129
lib/std/crypto/pcurves/p384/scalar.zig+4-4
......@@ -63,8 +63,8 @@ pub fn sub(a: CompressedScalar, b: CompressedScalar, endian: std.builtin.Endian)
6363}
6464
6565/// Return a random scalar
66pub fn random(endian: std.builtin.Endian) CompressedScalar {
67 return Scalar.random().toBytes(endian);
66pub fn random(io: std.Io, endian: std.builtin.Endian) CompressedScalar {
67 return Scalar.random(io).toBytes(endian);
6868}
6969
7070/// A scalar in unpacked representation.
......@@ -159,10 +159,10 @@ pub const Scalar = struct {
159159 }
160160
161161 /// Return a random scalar < L.
162 pub fn random() Scalar {
162 pub fn random(io: std.Io) Scalar {
163163 var s: [64]u8 = undefined;
164164 while (true) {
165 crypto.random.bytes(&s);
165 io.random(&s);
166166 const n = Scalar.fromBytes64(s, .little);
167167 if (!n.isZero()) {
168168 return n;
lib/std/crypto/pcurves/secp256k1.zig+2-2
......@@ -175,8 +175,8 @@ pub const Secp256k1 = struct {
175175 }
176176
177177 /// Return a random point.
178 pub fn random() Secp256k1 {
179 const n = scalar.random(.little);
178 pub fn random(io: std.Io) Secp256k1 {
179 const n = scalar.random(io, .little);
180180 return basePoint.mul(n, .little) catch unreachable;
181181 }
182182
lib/std/crypto/pcurves/secp256k1/scalar.zig+4-4
......@@ -68,8 +68,8 @@ pub fn sub(a: CompressedScalar, b: CompressedScalar, endian: std.builtin.Endian)
6868}
6969
7070/// Return a random scalar
71pub fn random(endian: std.builtin.Endian) CompressedScalar {
72 return Scalar.random().toBytes(endian);
71pub fn random(io: std.Io, endian: std.builtin.Endian) CompressedScalar {
72 return Scalar.random(io).toBytes(endian);
7373}
7474
7575/// A scalar in unpacked representation.
......@@ -170,10 +170,10 @@ pub const Scalar = struct {
170170 }
171171
172172 /// Return a random scalar < L.
173 pub fn random() Scalar {
173 pub fn random(io: std.Io) Scalar {
174174 var s: [48]u8 = undefined;
175175 while (true) {
176 crypto.random.bytes(&s);
176 io.random(&s);
177177 const n = Scalar.fromBytes48(s, .little);
178178 if (!n.isZero()) {
179179 return n;
lib/std/crypto/pcurves/tests/p256.zig+11-6
......@@ -5,8 +5,9 @@ const testing = std.testing;
55const P256 = @import("../p256.zig").P256;
66
77test "p256 ECDH key exchange" {
8 const dha = P256.scalar.random(.little);
9 const dhb = P256.scalar.random(.little);
8 const io = testing.io;
9 const dha = P256.scalar.random(io, .little);
10 const dhb = P256.scalar.random(io, .little);
1011 const dhA = try P256.basePoint.mul(dha, .little);
1112 const dhB = try P256.basePoint.mul(dhb, .little);
1213 const shareda = try dhA.mul(dhb, .little);
......@@ -66,28 +67,32 @@ test "p256 test vectors - doubling" {
6667}
6768
6869test "p256 compressed sec1 encoding/decoding" {
69 const p = P256.random();
70 const io = testing.io;
71 const p = P256.random(io);
7072 const s = p.toCompressedSec1();
7173 const q = try P256.fromSec1(&s);
7274 try testing.expect(p.equivalent(q));
7375}
7476
7577test "p256 uncompressed sec1 encoding/decoding" {
76 const p = P256.random();
78 const io = testing.io;
79 const p = P256.random(io);
7780 const s = p.toUncompressedSec1();
7881 const q = try P256.fromSec1(&s);
7982 try testing.expect(p.equivalent(q));
8083}
8184
8285test "p256 public key is the neutral element" {
86 const io = testing.io;
8387 const n = P256.scalar.Scalar.zero.toBytes(.little);
84 const p = P256.random();
88 const p = P256.random(io);
8589 try testing.expectError(error.IdentityElement, p.mul(n, .little));
8690}
8791
8892test "p256 public key is the neutral element (public verification)" {
93 const io = testing.io;
8994 const n = P256.scalar.Scalar.zero.toBytes(.little);
90 const p = P256.random();
95 const p = P256.random(io);
9196 try testing.expectError(error.IdentityElement, p.mulPublic(n, .little));
9297}
9398
lib/std/crypto/pcurves/tests/p384.zig+11-6
......@@ -5,8 +5,9 @@ const testing = std.testing;
55const P384 = @import("../p384.zig").P384;
66
77test "p384 ECDH key exchange" {
8 const dha = P384.scalar.random(.little);
9 const dhb = P384.scalar.random(.little);
8 const io = testing.io;
9 const dha = P384.scalar.random(io, .little);
10 const dhb = P384.scalar.random(io, .little);
1011 const dhA = try P384.basePoint.mul(dha, .little);
1112 const dhB = try P384.basePoint.mul(dhb, .little);
1213 const shareda = try dhA.mul(dhb, .little);
......@@ -67,7 +68,8 @@ test "p384 test vectors - doubling" {
6768}
6869
6970test "p384 compressed sec1 encoding/decoding" {
70 const p = P384.random();
71 const io = testing.io;
72 const p = P384.random(io);
7173 const s0 = p.toUncompressedSec1();
7274 const s = p.toCompressedSec1();
7375 try testing.expectEqualSlices(u8, s0[1..49], s[1..49]);
......@@ -76,21 +78,24 @@ test "p384 compressed sec1 encoding/decoding" {
7678}
7779
7880test "p384 uncompressed sec1 encoding/decoding" {
79 const p = P384.random();
81 const io = testing.io;
82 const p = P384.random(io);
8083 const s = p.toUncompressedSec1();
8184 const q = try P384.fromSec1(&s);
8285 try testing.expect(p.equivalent(q));
8386}
8487
8588test "p384 public key is the neutral element" {
89 const io = testing.io;
8690 const n = P384.scalar.Scalar.zero.toBytes(.little);
87 const p = P384.random();
91 const p = P384.random(io);
8892 try testing.expectError(error.IdentityElement, p.mul(n, .little));
8993}
9094
9195test "p384 public key is the neutral element (public verification)" {
96 const io = testing.io;
9297 const n = P384.scalar.Scalar.zero.toBytes(.little);
93 const p = P384.random();
98 const p = P384.random(io);
9499 try testing.expectError(error.IdentityElement, p.mulPublic(n, .little));
95100}
96101
lib/std/crypto/pcurves/tests/secp256k1.zig+14-8
......@@ -5,8 +5,9 @@ const testing = std.testing;
55const Secp256k1 = @import("../secp256k1.zig").Secp256k1;
66
77test "secp256k1 ECDH key exchange" {
8 const dha = Secp256k1.scalar.random(.little);
9 const dhb = Secp256k1.scalar.random(.little);
8 const io = testing.io;
9 const dha = Secp256k1.scalar.random(io, .little);
10 const dhb = Secp256k1.scalar.random(io, .little);
1011 const dhA = try Secp256k1.basePoint.mul(dha, .little);
1112 const dhB = try Secp256k1.basePoint.mul(dhb, .little);
1213 const shareda = try dhA.mul(dhb, .little);
......@@ -15,8 +16,9 @@ test "secp256k1 ECDH key exchange" {
1516}
1617
1718test "secp256k1 ECDH key exchange including public multiplication" {
18 const dha = Secp256k1.scalar.random(.little);
19 const dhb = Secp256k1.scalar.random(.little);
19 const io = testing.io;
20 const dha = Secp256k1.scalar.random(io, .little);
21 const dhb = Secp256k1.scalar.random(io, .little);
2022 const dhA = try Secp256k1.basePoint.mul(dha, .little);
2123 const dhB = try Secp256k1.basePoint.mulPublic(dhb, .little);
2224 const shareda = try dhA.mul(dhb, .little);
......@@ -77,28 +79,32 @@ test "secp256k1 test vectors - doubling" {
7779}
7880
7981test "secp256k1 compressed sec1 encoding/decoding" {
80 const p = Secp256k1.random();
82 const io = testing.io;
83 const p = Secp256k1.random(io);
8184 const s = p.toCompressedSec1();
8285 const q = try Secp256k1.fromSec1(&s);
8386 try testing.expect(p.equivalent(q));
8487}
8588
8689test "secp256k1 uncompressed sec1 encoding/decoding" {
87 const p = Secp256k1.random();
90 const io = testing.io;
91 const p = Secp256k1.random(io);
8892 const s = p.toUncompressedSec1();
8993 const q = try Secp256k1.fromSec1(&s);
9094 try testing.expect(p.equivalent(q));
9195}
9296
9397test "secp256k1 public key is the neutral element" {
98 const io = testing.io;
9499 const n = Secp256k1.scalar.Scalar.zero.toBytes(.little);
95 const p = Secp256k1.random();
100 const p = Secp256k1.random(io);
96101 try testing.expectError(error.IdentityElement, p.mul(n, .little));
97102}
98103
99104test "secp256k1 public key is the neutral element (public verification)" {
105 const io = testing.io;
100106 const n = Secp256k1.scalar.Scalar.zero.toBytes(.little);
101 const p = Secp256k1.random();
107 const p = Secp256k1.random(io);
102108 try testing.expectError(error.IdentityElement, p.mulPublic(n, .little));
103109}
104110
lib/std/crypto/salsa20.zig+19-15
......@@ -533,9 +533,9 @@ pub const SealedBox = struct {
533533
534534 /// Encrypt a message `m` for a recipient whose public key is `public_key`.
535535 /// `c` must be `seal_length` bytes larger than `m`, so that the required metadata can be added.
536 pub fn seal(c: []u8, m: []const u8, public_key: [public_length]u8) (WeakPublicKeyError || IdentityElementError)!void {
536 pub fn seal(io: std.Io, c: []u8, m: []const u8, public_key: [public_length]u8) (WeakPublicKeyError || IdentityElementError)!void {
537537 debug.assert(c.len == m.len + seal_length);
538 var ekp = KeyPair.generate();
538 var ekp = KeyPair.generate(io);
539539 const nonce = createNonce(ekp.public_key, public_key);
540540 c[0..public_length].* = ekp.public_key;
541541 try Box.seal(c[Box.public_length..], m, nonce, public_key, ekp.secret_key);
......@@ -573,29 +573,31 @@ test "(x)salsa20" {
573573}
574574
575575test "xsalsa20poly1305" {
576 const io = std.testing.io;
576577 var msg: [100]u8 = undefined;
577578 var msg2: [msg.len]u8 = undefined;
578579 var c: [msg.len]u8 = undefined;
579580 var key: [XSalsa20Poly1305.key_length]u8 = undefined;
580581 var nonce: [XSalsa20Poly1305.nonce_length]u8 = undefined;
581582 var tag: [XSalsa20Poly1305.tag_length]u8 = undefined;
582 crypto.random.bytes(&msg);
583 crypto.random.bytes(&key);
584 crypto.random.bytes(&nonce);
583 io.random(&msg);
584 io.random(&key);
585 io.random(&nonce);
585586
586587 XSalsa20Poly1305.encrypt(c[0..], &tag, msg[0..], "ad", nonce, key);
587588 try XSalsa20Poly1305.decrypt(msg2[0..], c[0..], tag, "ad", nonce, key);
588589}
589590
590591test "xsalsa20poly1305 secretbox" {
592 const io = std.testing.io;
591593 var msg: [100]u8 = undefined;
592594 var msg2: [msg.len]u8 = undefined;
593595 var key: [XSalsa20Poly1305.key_length]u8 = undefined;
594596 var nonce: [Box.nonce_length]u8 = undefined;
595597 var boxed: [msg.len + Box.tag_length]u8 = undefined;
596 crypto.random.bytes(&msg);
597 crypto.random.bytes(&key);
598 crypto.random.bytes(&nonce);
598 io.random(&msg);
599 io.random(&key);
600 io.random(&nonce);
599601
600602 SecretBox.seal(boxed[0..], msg[0..], nonce, key);
601603 try SecretBox.open(msg2[0..], boxed[0..], nonce, key);
......@@ -604,15 +606,16 @@ test "xsalsa20poly1305 secretbox" {
604606test "xsalsa20poly1305 box" {
605607 if (builtin.cpu.has(.riscv, .v) and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/24299
606608
609 const io = std.testing.io;
607610 var msg: [100]u8 = undefined;
608611 var msg2: [msg.len]u8 = undefined;
609612 var nonce: [Box.nonce_length]u8 = undefined;
610613 var boxed: [msg.len + Box.tag_length]u8 = undefined;
611 crypto.random.bytes(&msg);
612 crypto.random.bytes(&nonce);
614 io.random(&msg);
615 io.random(&nonce);
613616
614 const kp1 = Box.KeyPair.generate();
615 const kp2 = Box.KeyPair.generate();
617 const kp1 = Box.KeyPair.generate(io);
618 const kp2 = Box.KeyPair.generate(io);
616619 try Box.seal(boxed[0..], msg[0..], nonce, kp1.public_key, kp2.secret_key);
617620 try Box.open(msg2[0..], boxed[0..], nonce, kp2.public_key, kp1.secret_key);
618621}
......@@ -620,13 +623,14 @@ test "xsalsa20poly1305 box" {
620623test "xsalsa20poly1305 sealedbox" {
621624 if (builtin.cpu.has(.riscv, .v) and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/24299
622625
626 const io = std.testing.io;
623627 var msg: [100]u8 = undefined;
624628 var msg2: [msg.len]u8 = undefined;
625629 var boxed: [msg.len + SealedBox.seal_length]u8 = undefined;
626 crypto.random.bytes(&msg);
630 io.random(&msg);
627631
628 const kp = Box.KeyPair.generate();
629 try SealedBox.seal(boxed[0..], msg[0..], kp.public_key);
632 const kp = Box.KeyPair.generate(io);
633 try SealedBox.seal(io, boxed[0..], msg[0..], kp.public_key);
630634 try SealedBox.open(msg2[0..], boxed[0..], kp);
631635}
632636
lib/std/crypto/scrypt.zig+5-6
......@@ -20,7 +20,7 @@ const Error = pwhash.Error;
2020
2121const max_size = math.maxInt(usize);
2222const max_int = max_size >> 1;
23const default_salt_len = 32;
23pub const default_salt_len = 32;
2424const default_hash_len = 32;
2525const max_salt_len = 64;
2626const max_hash_len = 64;
......@@ -417,10 +417,9 @@ const PhcFormatHasher = struct {
417417 password: []const u8,
418418 params: Params,
419419 buf: []u8,
420 /// Filled with cryptographically secure entropy.
421 salt: []const u8,
420422 ) HasherError![]const u8 {
421 var salt: [default_salt_len]u8 = undefined;
422 crypto.random.bytes(&salt);
423
424423 var hash: [default_hash_len]u8 = undefined;
425424 try kdf(allocator, &hash, password, &salt, params);
426425
......@@ -466,9 +465,9 @@ const CryptFormatHasher = struct {
466465 password: []const u8,
467466 params: Params,
468467 buf: []u8,
468 /// Filled with cryptographically secure entropy.
469 salt_bin: []const u8,
469470 ) HasherError![]const u8 {
470 var salt_bin: [default_salt_len]u8 = undefined;
471 crypto.random.bytes(&salt_bin);
472471 const salt = crypt_format.saltFromBin(salt_bin.len, salt_bin);
473472
474473 var hash: [default_hash_len]u8 = undefined;
lib/std/crypto/timing_safe.zig+12-11
......@@ -180,24 +180,24 @@ pub fn declassify(ptr: anytype) void {
180180}
181181
182182test eql {
183 const random = std.crypto.random;
183 const io = std.testing.io;
184184 const expect = std.testing.expect;
185185 var a: [100]u8 = undefined;
186186 var b: [100]u8 = undefined;
187 random.bytes(a[0..]);
188 random.bytes(b[0..]);
187 io.random(&a);
188 io.random(&b);
189189 try expect(!eql([100]u8, a, b));
190190 a = b;
191191 try expect(eql([100]u8, a, b));
192192}
193193
194194test "eql (vectors)" {
195 const random = std.crypto.random;
195 const io = std.testing.io;
196196 const expect = std.testing.expect;
197197 var a: [100]u8 = undefined;
198198 var b: [100]u8 = undefined;
199 random.bytes(a[0..]);
200 random.bytes(b[0..]);
199 io.random(&a);
200 io.random(&b);
201201 const v1: @Vector(100, u8) = a;
202202 const v2: @Vector(100, u8) = b;
203203 try expect(!eql(@Vector(100, u8), v1, v2));
......@@ -220,9 +220,10 @@ test compare {
220220}
221221
222222test "add and sub" {
223 const io = std.testing.io;
224
223225 const expectEqual = std.testing.expectEqual;
224226 const expectEqualSlices = std.testing.expectEqualSlices;
225 const random = std.crypto.random;
226227 const len = 32;
227228 var a: [len]u8 = undefined;
228229 var b: [len]u8 = undefined;
......@@ -230,8 +231,8 @@ test "add and sub" {
230231 const zero = [_]u8{0} ** len;
231232 var iterations: usize = 100;
232233 while (iterations != 0) : (iterations -= 1) {
233 random.bytes(&a);
234 random.bytes(&b);
234 io.random(&a);
235 io.random(&b);
235236 const endian = if (iterations % 2 == 0) Endian.big else Endian.little;
236237 _ = sub(u8, &a, &b, &c, endian); // a-b
237238 _ = add(u8, &c, &b, &c, endian); // (a-b)+b
......@@ -243,11 +244,11 @@ test "add and sub" {
243244}
244245
245246test classify {
246 const random = std.crypto.random;
247 const io = std.testing.io;
247248 const expect = std.testing.expect;
248249
249250 var secret: [32]u8 = undefined;
250 random.bytes(&secret);
251 io.random(&secret);
251252
252253 // Input of the hash function is marked as secret
253254 classify(&secret);
lib/std/crypto/tls/Client.zig+7-7
......@@ -109,7 +109,7 @@ pub const Options = struct {
109109 read_buffer: []u8,
110110 /// Cryptographically secure random bytes. The pointer is not captured; data is only
111111 /// read during `init`.
112 entropy: *const [176]u8,
112 entropy: *const [240]u8,
113113 /// Current time according to the wall clock / calendar, in seconds.
114114 realtime_now_seconds: i64,
115115
......@@ -200,7 +200,7 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client
200200 var server_hello_rand: [32]u8 = undefined;
201201 const legacy_session_id = options.entropy[32..64].*;
202202
203 var key_share = KeyShare.init(options.entropy[64..176].*) catch |err| switch (err) {
203 var key_share = KeyShare.init(options.entropy[64..240]) catch |err| switch (err) {
204204 // Only possible to happen if the seed is all zeroes.
205205 error.IdentityElement => return error.InsufficientEntropy,
206206 };
......@@ -1330,12 +1330,12 @@ const KeyShare = struct {
13301330 crypto.dh.X25519.shared_length,
13311331 );
13321332
1333 fn init(seed: [112]u8) error{IdentityElement}!KeyShare {
1333 fn init(seed: *const [176]u8) error{IdentityElement}!KeyShare {
13341334 return .{
1335 .ml_kem768_kp = .generate(),
1336 .secp256r1_kp = try .generateDeterministic(seed[0..32].*),
1337 .secp384r1_kp = try .generateDeterministic(seed[32..80].*),
1338 .x25519_kp = try .generateDeterministic(seed[80..112].*),
1335 .ml_kem768_kp = try .generateDeterministic(seed[0..64].*),
1336 .secp256r1_kp = try .generateDeterministic(seed[64..96].*),
1337 .secp384r1_kp = try .generateDeterministic(seed[96..144].*),
1338 .x25519_kp = try .generateDeterministic(seed[144..176].*),
13391339 .sk_buf = undefined,
13401340 .sk_len = 0,
13411341 };
lib/std/fs/test.zig+1-1
......@@ -1761,7 +1761,7 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" {
17611761 const io = testing.io;
17621762
17631763 var random_bytes: [12]u8 = undefined;
1764 std.crypto.random.bytes(&random_bytes);
1764 io.random(&random_bytes);
17651765
17661766 var random_b64: [std.fs.base64_encoder.calcSize(random_bytes.len)]u8 = undefined;
17671767 _ = std.fs.base64_encoder.encode(&random_b64, &random_bytes);
lib/std/http/Client.zig+2-2
......@@ -321,8 +321,8 @@ pub const Connection = struct {
321321 assert(base.ptr + alloc_len == socket_read_buffer.ptr + socket_read_buffer.len);
322322 @memcpy(host_buffer, remote_host.bytes);
323323 const tls: *Tls = @ptrCast(base);
324 var random_buffer: [176]u8 = undefined;
325 std.crypto.random.bytes(&random_buffer);
324 var random_buffer: [240]u8 = undefined;
325 io.random(&random_buffer);
326326 tls.* = .{
327327 .connection = .{
328328 .client = client,
lib/std/os/linux/tls.zig+5-7
......@@ -531,13 +531,11 @@ pub fn prepareArea(area: []u8) usize {
531531 };
532532}
533533
534/// The main motivation for the size chosen here is that this is how much ends up being requested for
535/// the thread-local variables of the `std.crypto.random` implementation. I'm not sure why it ends up
536/// being so much; the struct itself is only 64 bytes. I think it has to do with being page-aligned
537/// and LLVM or LLD is not smart enough to lay out the TLS data in a space-conserving way. Anyway, I
538/// think it's fine because it's less than 3 pages of memory, and putting it in the ELF like this is
539/// equivalent to moving the `mmap` call below into the kernel, avoiding syscall overhead.
540var main_thread_area_buffer: [0x2100]u8 align(page_size_min) = undefined;
534/// The main motivation for the size chosen here is to be larger than total
535/// amount of thread-local variables for most programs. Putting this allocation
536/// in the ELF like this is equivalent to moving the `mmap` call below into the
537/// kernel, avoiding syscall overhead.
538var main_thread_area_buffer: [0x1000]u8 align(page_size_min) = undefined;
541539
542540/// Computes the layout of the static TLS area, allocates the area, initializes all of its fields,
543541/// and assigns the architecture-specific value to the TP register.
lib/std/posix/test.zig-10
......@@ -33,16 +33,6 @@ test "check WASI CWD" {
3333 }
3434}
3535
36test "getrandom" {
37 var buf_a: [50]u8 = undefined;
38 var buf_b: [50]u8 = undefined;
39 try posix.getrandom(&buf_a);
40 try posix.getrandom(&buf_b);
41 // If this test fails the chance is significantly higher that there is a bug than
42 // that two sets of 50 bytes were equal.
43 try expect(!mem.eql(u8, &buf_a, &buf_b));
44}
45
4636test "getuid" {
4737 if (native_os == .windows or native_os == .wasi) return error.SkipZigTest;
4838 _ = posix.getuid();
lib/std/testing.zig+1-1
......@@ -631,7 +631,7 @@ pub const TmpDir = struct {
631631pub fn tmpDir(opts: Io.Dir.OpenOptions) TmpDir {
632632 comptime assert(builtin.is_test);
633633 var random_bytes: [TmpDir.random_bytes_count]u8 = undefined;
634 std.crypto.random.bytes(&random_bytes);
634 io.random(&random_bytes);
635635 var sub_path: [TmpDir.sub_path_len]u8 = undefined;
636636 _ = std.fs.base64_encoder.encode(&sub_path, &random_bytes);
637637
src/Compilation.zig+13-4
......@@ -2942,7 +2942,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
29422942 .none => |none| {
29432943 assert(none.tmp_artifact_directory == null);
29442944 none.tmp_artifact_directory = d: {
2945 tmp_dir_rand_int = std.crypto.random.int(u64);
2945 io.random(@ptrCast(&tmp_dir_rand_int));
29462946 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int);
29472947 const path = try comp.dirs.local_cache.join(arena, &.{tmp_dir_sub_path});
29482948 const handle = comp.dirs.local_cache.handle.createDirPathOpen(io, tmp_dir_sub_path, .{}) catch |err| {
......@@ -3023,7 +3023,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
30233023
30243024 // Compile the artifacts to a temporary directory.
30253025 whole.tmp_artifact_directory = d: {
3026 tmp_dir_rand_int = std.crypto.random.int(u64);
3026 io.random(@ptrCast(&tmp_dir_rand_int));
30273027 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int);
30283028 const path = try comp.dirs.local_cache.join(arena, &.{tmp_dir_sub_path});
30293029 const handle = comp.dirs.local_cache.handle.createDirPathOpen(io, tmp_dir_sub_path, .{}) catch |err| {
......@@ -5759,7 +5759,11 @@ pub fn translateC(
57595759
57605760 const gpa = comp.gpa;
57615761 const io = comp.io;
5762 const tmp_basename = std.fmt.hex(std.crypto.random.int(u64));
5762 const tmp_basename = r: {
5763 var x: u64 = undefined;
5764 io.random(@ptrCast(&x));
5765 break :r std.fmt.hex(x);
5766 };
57635767 const tmp_sub_path = "tmp" ++ fs.path.sep_str ++ tmp_basename;
57645768 const cache_dir = comp.dirs.local_cache.handle;
57655769 var cache_tmp_dir = try cache_dir.createDirPathOpen(io, tmp_sub_path, .{});
......@@ -6889,8 +6893,13 @@ fn spawnZigRc(
68896893}
68906894
68916895pub fn tmpFilePath(comp: Compilation, ally: Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 {
6896 const io = comp.io;
6897 const rand_int = r: {
6898 var x: u64 = undefined;
6899 io.random(@ptrCast(&x));
6900 break :r x;
6901 };
68926902 const s = fs.path.sep_str;
6893 const rand_int = std.crypto.random.int(u64);
68946903 if (comp.dirs.local_cache.path) |p| {
68956904 return std.fmt.allocPrint(ally, "{s}" ++ s ++ "tmp" ++ s ++ "{x}-{s}", .{ p, rand_int, suffix });
68966905 } else {
src/Package.zig+2-2
......@@ -14,9 +14,9 @@ pub const Fingerprint = packed struct(u64) {
1414 id: u32,
1515 checksum: u32,
1616
17 pub fn generate(name: []const u8) Fingerprint {
17 pub fn generate(rng: std.Random, name: []const u8) Fingerprint {
1818 return .{
19 .id = std.crypto.random.intRangeLessThan(u32, 1, 0xffffffff),
19 .id = rng.intRangeLessThan(u32, 1, 0xffffffff),
2020 .checksum = std.hash.Crc32.hash(name),
2121 };
2222 }
src/Package/Fetch.zig+13-3
......@@ -494,7 +494,11 @@ fn runResource(
494494 const eb = &f.error_bundle;
495495 const s = fs.path.sep_str;
496496 const cache_root = f.job_queue.global_cache;
497 const rand_int = std.crypto.random.int(u64);
497 const rand_int = r: {
498 var x: u64 = undefined;
499 io.random(@ptrCast(&x));
500 break :r x;
501 };
498502 const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(rand_int);
499503
500504 const package_sub_path = blk: {
......@@ -690,7 +694,9 @@ fn loadManifest(f: *Fetch, pkg_root: Cache.Path) RunError!void {
690694 return error.FetchFailed;
691695 }
692696
693 f.manifest = try Manifest.parse(arena, ast.*, .{
697 const rng: std.Random.IoSource = .{ .io = io };
698
699 f.manifest = try Manifest.parse(arena, ast.*, rng.interface(), .{
694700 .allow_missing_paths_field = f.allow_missing_paths_field,
695701 .allow_missing_fingerprint = f.allow_missing_fingerprint,
696702 .allow_name_string = f.allow_name_string,
......@@ -1305,7 +1311,11 @@ fn unzip(
13051311 zip_path[prefix.len + random_len ..].* = suffix.*;
13061312
13071313 var zip_file = while (true) {
1308 const random_integer = std.crypto.random.int(u64);
1314 const random_integer = r: {
1315 var x: u64 = undefined;
1316 io.random(@ptrCast(&x));
1317 break :r x;
1318 };
13091319 zip_path[prefix.len..][0..random_len].* = std.fmt.hex(random_integer);
13101320
13111321 break cache_root.handle.createFile(io, &zip_path, .{
src/Package/Manifest.zig+5-5
......@@ -57,7 +57,7 @@ pub const ParseOptions = struct {
5757
5858pub const Error = Allocator.Error;
5959
60pub fn parse(gpa: Allocator, ast: Ast, options: ParseOptions) Error!Manifest {
60pub fn parse(gpa: Allocator, ast: Ast, rng: std.Random, options: ParseOptions) Error!Manifest {
6161 const main_node_index = ast.nodeData(.root).node;
6262
6363 var arena_instance = std.heap.ArenaAllocator.init(gpa);
......@@ -87,7 +87,7 @@ pub fn parse(gpa: Allocator, ast: Ast, options: ParseOptions) Error!Manifest {
8787 defer p.dependencies.deinit(gpa);
8888 defer p.paths.deinit(gpa);
8989
90 p.parseRoot(main_node_index) catch |err| switch (err) {
90 p.parseRoot(main_node_index, rng) catch |err| switch (err) {
9191 error.ParseFailure => assert(p.errors.items.len > 0),
9292 else => |e| return e,
9393 };
......@@ -157,7 +157,7 @@ const Parse = struct {
157157
158158 const InnerError = error{ ParseFailure, OutOfMemory };
159159
160 fn parseRoot(p: *Parse, node: Ast.Node.Index) !void {
160 fn parseRoot(p: *Parse, node: Ast.Node.Index, rng: std.Random) !void {
161161 const ast = p.ast;
162162 const main_token = ast.nodeMainToken(node);
163163
......@@ -217,13 +217,13 @@ const Parse = struct {
217217 if (fingerprint) |n| {
218218 if (!n.validate(p.name)) {
219219 return fail(p, main_token, "invalid fingerprint: 0x{x}; if this is a new or forked package, use this value: 0x{x}", .{
220 n.int(), Package.Fingerprint.generate(p.name).int(),
220 n.int(), Package.Fingerprint.generate(rng, p.name).int(),
221221 });
222222 }
223223 p.id = n.id;
224224 } else if (!p.allow_missing_fingerprint) {
225225 try appendError(p, main_token, "missing top-level 'fingerprint' field; suggested value: 0x{x}", .{
226 Package.Fingerprint.generate(p.name).int(),
226 Package.Fingerprint.generate(rng, p.name).int(),
227227 });
228228 } else {
229229 p.id = 0;
src/link.zig+6-1
......@@ -616,8 +616,13 @@ pub const File = struct {
616616 // it will return ETXTBSY. So instead, we copy the file, atomically rename it
617617 // over top of the exe path, and then proceed normally. This changes the inode,
618618 // avoiding the error.
619 const random_integer = r: {
620 var x: u32 = undefined;
621 io.random(@ptrCast(&x));
622 break :r x;
623 };
619624 const tmp_sub_path = try std.fmt.allocPrint(gpa, "{s}-{x}", .{
620 emit.sub_path, std.crypto.random.int(u32),
625 emit.sub_path, random_integer,
621626 });
622627 defer gpa.free(tmp_sub_path);
623628 try emit.root_dir.handle.copyFile(emit.sub_path, emit.root_dir.handle, tmp_sub_path, io, .{});
src/link/Lld.zig+5-1
......@@ -1636,7 +1636,11 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi
16361636 const err = switch (first_err) {
16371637 error.NameTooLong => err: {
16381638 const s = fs.path.sep_str;
1639 const rand_int = std.crypto.random.int(u64);
1639 const rand_int = r: {
1640 var x: u64 = undefined;
1641 io.random(@ptrCast(&x));
1642 break :r x;
1643 };
16401644 const rsp_path = "tmp" ++ s ++ std.fmt.hex(rand_int) ++ ".rsp";
16411645
16421646 const rsp_file = try comp.dirs.local_cache.handle.createFile(io, rsp_path, .{});
src/main.zig+19-12
......@@ -3395,7 +3395,7 @@ fn buildOutputType(
33953395 // "-" is stdin. Dump it to a real file.
33963396 const sep = fs.path.sep_str;
33973397 const dump_path = try std.fmt.allocPrint(arena, "tmp" ++ sep ++ "{x}-dump-stdin{s}", .{
3398 std.crypto.random.int(u64), ext.canonicalName(target),
3398 randInt(io, u64), ext.canonicalName(target),
33993399 });
34003400 try dirs.local_cache.handle.createDirPath(io, "tmp");
34013401
......@@ -4433,7 +4433,7 @@ fn runOrTest(
44334433 try argv.append(exe_path);
44344434 if (arg_mode == .zig_test) {
44354435 try argv.append(
4436 try std.fmt.allocPrint(arena, "--seed=0x{x}", .{std.crypto.random.int(u32)}),
4436 try std.fmt.allocPrint(arena, "--seed=0x{x}", .{randInt(io, u32)}),
44374437 );
44384438 }
44394439 } else {
......@@ -4763,7 +4763,8 @@ fn cmdInit(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !
47634763 const cwd_basename = fs.path.basename(cwd_path);
47644764 const sanitized_root_name = try sanitizeExampleName(arena, cwd_basename);
47654765
4766 const fingerprint: Package.Fingerprint = .generate(sanitized_root_name);
4766 const rng: std.Random.IoSource = .{ .io = io };
4767 const fingerprint: Package.Fingerprint = .generate(rng.interface(), sanitized_root_name);
47674768
47684769 switch (template) {
47694770 .example => {
......@@ -4919,7 +4920,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8,
49194920
49204921 try child_argv.appendSlice(&.{
49214922 "--seed",
4922 try std.fmt.allocPrint(arena, "0x{x}", .{std.crypto.random.int(u32)}),
4923 try std.fmt.allocPrint(arena, "0x{x}", .{randInt(io, u32)}),
49234924 });
49244925 const argv_index_seed = child_argv.items.len - 1;
49254926
......@@ -4937,7 +4938,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8,
49374938 // the strategy is to choose a temporary file name ahead of time, and then
49384939 // read this file in the parent to obtain the results, in the case the child
49394940 // exits with code 3.
4940 const results_tmp_file_nonce = std.fmt.hex(std.crypto.random.int(u64));
4941 const results_tmp_file_nonce = std.fmt.hex(randInt(io, u64));
49414942 try child_argv.append("-Z" ++ results_tmp_file_nonce);
49424943
49434944 var color: Color = .auto;
......@@ -7223,7 +7224,7 @@ fn createDependenciesModule(
72237224) !*Package.Module {
72247225 // Atomically create the file in a directory named after the hash of its contents.
72257226 const basename = "dependencies.zig";
7226 const rand_int = std.crypto.random.int(u64);
7227 const rand_int = randInt(io, u64);
72277228 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);
72287229 {
72297230 var tmp_dir = try dirs.local_cache.handle.createDirPathOpen(io, tmp_dir_sub_path, .{});
......@@ -7339,6 +7340,8 @@ fn loadManifest(
73397340 io: Io,
73407341 options: LoadManifestOptions,
73417342) !struct { Package.Manifest, Ast } {
7343 const rng: std.Random.IoSource = .{ .io = io };
7344
73427345 const manifest_bytes = while (true) {
73437346 break options.dir.readFileAllocOptions(
73447347 io,
......@@ -7360,15 +7363,13 @@ fn loadManifest(
73607363 , .{
73617364 options.root_name,
73627365 build_options.version,
7363 Package.Fingerprint.generate(options.root_name).int(),
7366 Package.Fingerprint.generate(rng.interface(), options.root_name).int(),
73647367 }) catch |e| {
7365 fatal("unable to write {s}: {s}", .{ Package.Manifest.basename, @errorName(e) });
7368 fatal("unable to write {s}: {t}", .{ Package.Manifest.basename, e });
73667369 };
73677370 continue;
73687371 },
7369 else => |e| fatal("unable to load {s}: {s}", .{
7370 Package.Manifest.basename, @errorName(e),
7371 }),
7372 else => |e| fatal("unable to load {s}: {t}", .{ Package.Manifest.basename, e }),
73727373 };
73737374 };
73747375 var ast = try Ast.parse(gpa, manifest_bytes, .zon);
......@@ -7379,7 +7380,7 @@ fn loadManifest(
73797380 process.exit(2);
73807381 }
73817382
7382 var manifest = try Package.Manifest.parse(gpa, ast, .{});
7383 var manifest = try Package.Manifest.parse(gpa, ast, rng.interface(), .{});
73837384 errdefer manifest.deinit(gpa);
73847385
73857386 if (manifest.errors.len > 0) {
......@@ -7632,3 +7633,9 @@ fn setThreadLimit(n: usize) void {
76327633 threaded_impl_ptr.setAsyncLimit(limit);
76337634 threaded_impl_ptr.concurrent_limit = limit;
76347635}
7636
7637fn randInt(io: Io, comptime T: type) T {
7638 var x: T = undefined;
7639 io.random(@ptrCast(&x));
7640 return x;
7641}
test/standalone/simple/guess_number/main.zig+2-1
......@@ -10,7 +10,8 @@ pub fn main(init: std.process.Init) !void {
1010
1111 try out.writeAll("Welcome to the Guess Number Game in Zig.\n");
1212
13 const answer = std.crypto.random.intRangeLessThan(u8, 0, 100) + 1;
13 var rng: std.Random.IoSource = .{ .io = init.io };
14 const answer = rng.interface().intRangeLessThan(u8, 0, 100) + 1;
1415
1516 while (true) {
1617 try out.writeAll("\nGuess a number between 1 and 100: ");
tools/doctest.zig+4-3
......@@ -78,9 +78,10 @@ pub fn main(init: std.process.Init) !void {
7878 const code = try parseManifest(arena, source_bytes);
7979 const source = stripManifest(source_bytes);
8080
81 const tmp_dir_path = try std.fmt.allocPrint(arena, "{s}/tmp/{x}", .{
82 cache_root, std.crypto.random.int(u64),
83 });
81 var random_integer: u64 = undefined;
82 io.random(@ptrCast(&random_integer));
83
84 const tmp_dir_path = try std.fmt.allocPrint(arena, "{s}/tmp/{x}", .{ cache_root, random_integer });
8485 Dir.cwd().createDirPath(io, tmp_dir_path) catch |err|
8586 fatal("unable to create tmp dir '{s}': {t}", .{ tmp_dir_path, err });
8687 defer Dir.cwd().deleteTree(io, tmp_dir_path) catch |err| std.log.err("unable to delete '{s}': {t}", .{
tools/incr-check.zig+9-4
......@@ -100,7 +100,7 @@ pub fn main(init: std.process.Init) !void {
100100 const prog_node = std.Progress.start(io, .{});
101101 defer prog_node.end();
102102
103 const rand_int = std.crypto.random.int(u64);
103 const rand_int = rand64(io);
104104 const tmp_dir_path = "tmp_" ++ std.fmt.hex(rand_int);
105105 var tmp_dir = try Dir.cwd().createDirPathOpen(io, tmp_dir_path, .{});
106106 defer {
......@@ -452,20 +452,19 @@ const Eval = struct {
452452 std.debug.assert(eval.target.backend == .sema);
453453 return;
454454 };
455 const io = eval.io;
455456
456457 const binary_path = switch (eval.target.backend) {
457458 .sema => unreachable,
458459 .selfhosted, .llvm => emitted_path,
459460 .cbe => bin: {
460 const rand_int = std.crypto.random.int(u64);
461 const rand_int = rand64(io);
461462 const out_bin_name = "./out_" ++ std.fmt.hex(rand_int);
462463 try eval.buildCOutput(emitted_path, out_bin_name, prog_node);
463464 break :bin out_bin_name;
464465 },
465466 };
466467
467 const io = eval.io;
468
469468 var argv_buf: [2][]const u8 = undefined;
470469 const argv: []const []const u8, const is_foreign: bool = sw: switch (std.zig.system.getExternalExecutor(
471470 io,
......@@ -957,3 +956,9 @@ fn parseExpectedError(str: []const u8, l: usize) Case.ExpectedError {
957956 .msg = message,
958957 };
959958}
959
960fn rand64(io: Io) u64 {
961 var x: u64 = undefined;
962 io.random(@ptrCast(&x));
963 return x;
964}