| author | |
| committer | |
| log | 1f1381a866a110953f9950d8c0c6497a2567daa0 |
| tree | 458e258f1ea98c691ebbd41b353c65b676b4ff8a |
| parent | 81a35a86ea9385016f371213a2b72b14902bb955 |
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 |
| 1217 | 1217 | } |
| 1218 | 1218 | |
| 1219 | 1219 | fn getRandomFilename(d: *Driver, buf: *[std.fs.max_name_bytes]u8, extension: []const u8) ![]const u8 { |
| 1220 | const io = d.comp.io; | |
| 1220 | 1221 | const random_bytes_count = 12; |
| 1221 | 1222 | const sub_path_len = comptime std.fs.base64_encoder.calcSize(random_bytes_count); |
| 1222 | 1223 | |
| 1223 | 1224 | var random_bytes: [random_bytes_count]u8 = undefined; |
| 1224 | std.crypto.random.bytes(&random_bytes); | |
| 1225 | io.random(&random_bytes); | |
| 1225 | 1226 | var random_name: [sub_path_len]u8 = undefined; |
| 1226 | 1227 | _ = std.fs.base64_encoder.encode(&random_name, &random_bytes); |
| 1227 | 1228 |
lib/std/Io/Threaded.zig+49-16| ... | ... | @@ -78,7 +78,7 @@ pub const Csprng = struct { |
| 78 | 78 | pub const seed_len = std.Random.DefaultCsprng.secret_seed_length; |
| 79 | 79 | |
| 80 | 80 | 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); | |
| 82 | 82 | } |
| 83 | 83 | }; |
| 84 | 84 | |
| ... | ... | @@ -2395,11 +2395,11 @@ fn dirCreateDirPath( |
| 2395 | 2395 | status = .created; |
| 2396 | 2396 | } else |err| switch (err) { |
| 2397 | 2397 | 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; | |
| 2403 | 2403 | }, |
| 2404 | 2404 | error.FileNotFound => |e| { |
| 2405 | 2405 | component = it.previous() orelse return e; |
| ... | ... | @@ -2740,6 +2740,35 @@ fn dirStatFileWasi( |
| 2740 | 2740 | } |
| 2741 | 2741 | } |
| 2742 | 2742 | |
| 2743 | fn 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 | ||
| 2743 | 2772 | fn fileLength(userdata: ?*anyopaque, file: File) File.LengthError!u64 { |
| 2744 | 2773 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 2745 | 2774 | |
| ... | ... | @@ -12310,16 +12339,7 @@ fn statFromLinux(stx: *const std.os.linux.Statx) Io.UnexpectedError!File.Stat { |
| 12310 | 12339 | .nlink = stx.nlink, |
| 12311 | 12340 | .size = stx.size, |
| 12312 | 12341 | .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), | |
| 12323 | 12343 | .atime = if (!stx.mask.ATIME) null else .{ |
| 12324 | 12344 | .nanoseconds = @intCast(@as(i128, stx.atime.sec) * std.time.ns_per_s + stx.atime.nsec), |
| 12325 | 12345 | }, |
| ... | ... | @@ -12328,6 +12348,19 @@ fn statFromLinux(stx: *const std.os.linux.Statx) Io.UnexpectedError!File.Stat { |
| 12328 | 12348 | }; |
| 12329 | 12349 | } |
| 12330 | 12350 | |
| 12351 | fn 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 | ||
| 12331 | 12364 | fn statFromPosix(st: *const posix.Stat) File.Stat { |
| 12332 | 12365 | const atime = st.atime(); |
| 12333 | 12366 | 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" { |
| 275 | 275 | |
| 276 | 276 | const io = testing.io; |
| 277 | 277 | |
| 278 | const socket_path = try generateFileName("socket.unix"); | |
| 278 | const socket_path = try generateFileName(io, "socket.unix"); | |
| 279 | 279 | defer testing.allocator.free(socket_path); |
| 280 | 280 | |
| 281 | 281 | const socket_addr = try net.UnixAddress.init(socket_path); |
| ... | ... | @@ -308,11 +308,11 @@ test "listen on a unix socket, send bytes, receive bytes" { |
| 308 | 308 | try testing.expectEqualSlices(u8, "Hello world!", buf[0..n]); |
| 309 | 309 | } |
| 310 | 310 | |
| 311 | fn generateFileName(base_name: []const u8) ![]const u8 { | |
| 311 | fn generateFileName(io: Io, base_name: []const u8) ![]const u8 { | |
| 312 | 312 | const random_bytes_count = 12; |
| 313 | 313 | const sub_path_len = comptime std.fs.base64_encoder.calcSize(random_bytes_count); |
| 314 | 314 | var random_bytes: [12]u8 = undefined; |
| 315 | std.crypto.random.bytes(&random_bytes); | |
| 315 | io.random(&random_bytes); | |
| 316 | 316 | var sub_path: [sub_path_len]u8 = undefined; |
| 317 | 317 | _ = std.fs.base64_encoder.encode(&sub_path, &random_bytes); |
| 318 | 318 | 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" { |
| 565 | 565 | try group.concurrent(io, global.waitThenSpawn, .{ io, &group }); |
| 566 | 566 | } |
| 567 | 567 | |
| 568 | test "CSPRNG" { | |
| 568 | test "random" { | |
| 569 | 569 | const io = testing.io; |
| 570 | 570 | |
| 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)); | |
| 572 | 578 | |
| 573 | const a = random.int(u64); | |
| 574 | const b = random.int(u64); | |
| 575 | const c = random.int(u64); | |
| 576 | 579 | try std.testing.expect(a ^ b ^ c != 0); |
| 577 | 580 | } |
| 581 | ||
| 582 | test "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 { |
| 38 | 38 | |
| 39 | 39 | pub fn interface(this: *const @This()) std.Random { |
| 40 | 40 | return .{ |
| 41 | .ptr = this, | |
| 41 | .ptr = @constCast(this), | |
| 42 | 42 | .fillFn = fill, |
| 43 | 43 | }; |
| 44 | 44 | } |
lib/std/Random/test.zig+2-1| ... | ... | @@ -436,8 +436,9 @@ fn testRangeBias(r: Random, start: i8, end: i8, biased: bool) !void { |
| 436 | 436 | } |
| 437 | 437 | |
| 438 | 438 | test "CSPRNG" { |
| 439 | const io = std.testing.io; | |
| 439 | 440 | var secret_seed: [DefaultCsprng.secret_seed_length]u8 = undefined; |
| 440 | std.crypto.random.bytes(&secret_seed); | |
| 441 | io.random(&secret_seed); | |
| 441 | 442 | var csprng = DefaultCsprng.init(secret_seed); |
| 442 | 443 | const random = csprng.random(); |
| 443 | 444 | const a = random.int(u64); |
lib/std/crypto.zig+4| ... | ... | @@ -303,6 +303,9 @@ test { |
| 303 | 303 | _ = dh.X25519; |
| 304 | 304 | |
| 305 | 305 | _ = kem.kyber_d00; |
| 306 | _ = kem.hybrid; | |
| 307 | _ = kem.kyber_d00; | |
| 308 | _ = kem.ml_kem; | |
| 306 | 309 | |
| 307 | 310 | _ = ecc.Curve25519; |
| 308 | 311 | _ = ecc.Edwards25519; |
| ... | ... | @@ -340,6 +343,7 @@ test { |
| 340 | 343 | |
| 341 | 344 | _ = sign.Ed25519; |
| 342 | 345 | _ = sign.ecdsa; |
| 346 | _ = sign.mldsa; | |
| 343 | 347 | |
| 344 | 348 | _ = stream.chacha.ChaCha20IETF; |
| 345 | 349 | _ = stream.chacha.ChaCha12IETF; |
lib/std/crypto/25519/ed25519.zig+32-23| ... | ... | @@ -333,12 +333,10 @@ pub const Ed25519 = struct { |
| 333 | 333 | } |
| 334 | 334 | |
| 335 | 335 | /// 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 { | |
| 339 | 337 | var random_seed: [seed_length]u8 = undefined; |
| 340 | 338 | while (true) { |
| 341 | crypto.random.bytes(&random_seed); | |
| 339 | io.random(&random_seed); | |
| 342 | 340 | return generateDeterministic(random_seed) catch { |
| 343 | 341 | @branchHint(.unlikely); |
| 344 | 342 | continue; |
| ... | ... | @@ -389,18 +387,21 @@ pub const Ed25519 = struct { |
| 389 | 387 | |
| 390 | 388 | /// Create a Signer, that can be used for incremental signing. |
| 391 | 389 | /// 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 { | |
| 395 | 398 | if (!mem.eql(u8, &key_pair.secret_key.publicKeyBytes(), &key_pair.public_key.toBytes())) { |
| 396 | 399 | return error.KeyMismatch; |
| 397 | 400 | } |
| 398 | 401 | const scalar_and_prefix = key_pair.secret_key.scalarAndPrefix(); |
| 399 | 402 | var h = Sha512.init(.{}); |
| 400 | 403 | 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); | |
| 404 | 405 | if (noise) |*z| { |
| 405 | 406 | h.update(z); |
| 406 | 407 | } |
| ... | ... | @@ -420,7 +421,7 @@ pub const Ed25519 = struct { |
| 420 | 421 | }; |
| 421 | 422 | |
| 422 | 423 | /// 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 { | |
| 424 | 425 | var r_batch: [count]CompressedScalar = undefined; |
| 425 | 426 | var s_batch: [count]CompressedScalar = undefined; |
| 426 | 427 | var a_batch: [count]Curve = undefined; |
| ... | ... | @@ -454,7 +455,7 @@ pub const Ed25519 = struct { |
| 454 | 455 | |
| 455 | 456 | var z_batch: [count]Curve.scalar.CompressedScalar = undefined; |
| 456 | 457 | for (&z_batch) |*z| { |
| 457 | crypto.random.bytes(z[0..16]); | |
| 458 | io.random(z[0..16]); | |
| 458 | 459 | @memset(z[16..], 0); |
| 459 | 460 | } |
| 460 | 461 | |
| ... | ... | @@ -587,12 +588,14 @@ test "signature" { |
| 587 | 588 | } |
| 588 | 589 | |
| 589 | 590 | test "batch verification" { |
| 591 | const io = std.testing.io; | |
| 592 | ||
| 590 | 593 | for (0..16) |_| { |
| 591 | const key_pair = Ed25519.KeyPair.generate(); | |
| 594 | const key_pair = Ed25519.KeyPair.generate(io); | |
| 592 | 595 | var msg1: [32]u8 = undefined; |
| 593 | 596 | var msg2: [32]u8 = undefined; |
| 594 | crypto.random.bytes(&msg1); | |
| 595 | crypto.random.bytes(&msg2); | |
| 597 | io.random(&msg1); | |
| 598 | io.random(&msg2); | |
| 596 | 599 | const sig1 = try key_pair.sign(&msg1, null); |
| 597 | 600 | const sig2 = try key_pair.sign(&msg2, null); |
| 598 | 601 | var signature_batch = [_]Ed25519.BatchElement{ |
| ... | ... | @@ -607,10 +610,10 @@ test "batch verification" { |
| 607 | 610 | .public_key = key_pair.public_key, |
| 608 | 611 | }, |
| 609 | 612 | }; |
| 610 | try Ed25519.verifyBatch(2, signature_batch); | |
| 613 | try Ed25519.verifyBatch(io, 2, signature_batch); | |
| 611 | 614 | |
| 612 | 615 | 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)); | |
| 614 | 617 | } |
| 615 | 618 | } |
| 616 | 619 | |
| ... | ... | @@ -718,14 +721,15 @@ test "test vectors" { |
| 718 | 721 | } |
| 719 | 722 | |
| 720 | 723 | test "with blind keys" { |
| 724 | const io = std.testing.io; | |
| 721 | 725 | const BlindKeyPair = Ed25519.key_blinding.BlindKeyPair; |
| 722 | 726 | |
| 723 | 727 | // Create a standard Ed25519 key pair |
| 724 | const kp = Ed25519.KeyPair.generate(); | |
| 728 | const kp = Ed25519.KeyPair.generate(io); | |
| 725 | 729 | |
| 726 | 730 | // Create a random blinding seed |
| 727 | 731 | var blind: [32]u8 = undefined; |
| 728 | crypto.random.bytes(&blind); | |
| 732 | io.random(&blind); | |
| 729 | 733 | |
| 730 | 734 | // Blind the key pair |
| 731 | 735 | const blind_kp = try BlindKeyPair.init(kp, blind, "ctx"); |
| ... | ... | @@ -741,9 +745,12 @@ test "with blind keys" { |
| 741 | 745 | } |
| 742 | 746 | |
| 743 | 747 | test "signatures with streaming" { |
| 744 | const kp = Ed25519.KeyPair.generate(); | |
| 748 | const io = std.testing.io; | |
| 749 | const kp = Ed25519.KeyPair.generate(io); | |
| 745 | 750 | |
| 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); | |
| 747 | 754 | signer.update("mes"); |
| 748 | 755 | signer.update("sage"); |
| 749 | 756 | const sig = signer.finalize(); |
| ... | ... | @@ -757,7 +764,8 @@ test "signatures with streaming" { |
| 757 | 764 | } |
| 758 | 765 | |
| 759 | 766 | test "key pair from secret key" { |
| 760 | const kp = Ed25519.KeyPair.generate(); | |
| 767 | const io = std.testing.io; | |
| 768 | const kp = Ed25519.KeyPair.generate(io); | |
| 761 | 769 | const kp2 = try Ed25519.KeyPair.fromSecretKey(kp.secret_key); |
| 762 | 770 | try std.testing.expectEqualSlices(u8, &kp.secret_key.toBytes(), &kp2.secret_key.toBytes()); |
| 763 | 771 | try std.testing.expectEqualSlices(u8, &kp.public_key.toBytes(), &kp2.public_key.toBytes()); |
| ... | ... | @@ -788,7 +796,8 @@ test "cofactored vs cofactorless verification" { |
| 788 | 796 | } |
| 789 | 797 | |
| 790 | 798 | test "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); | |
| 792 | 801 | const msg = "test message"; |
| 793 | 802 | const sig = try kp.sign(msg, null); |
| 794 | 803 | try sig.verify(msg, kp.public_key); |
lib/std/crypto/25519/edwards25519.zig+5-3| ... | ... | @@ -575,10 +575,11 @@ test "packing/unpacking" { |
| 575 | 575 | } |
| 576 | 576 | |
| 577 | 577 | test "point addition/subtraction" { |
| 578 | const io = std.testing.io; | |
| 578 | 579 | var s1: [32]u8 = undefined; |
| 579 | 580 | var s2: [32]u8 = undefined; |
| 580 | crypto.random.bytes(&s1); | |
| 581 | crypto.random.bytes(&s2); | |
| 581 | io.random(&s1); | |
| 582 | io.random(&s2); | |
| 582 | 583 | const p = try Edwards25519.basePoint.clampedMul(s1); |
| 583 | 584 | const q = try Edwards25519.basePoint.clampedMul(s2); |
| 584 | 585 | const r = p.add(q).add(q).sub(q).sub(q); |
| ... | ... | @@ -622,9 +623,10 @@ test "implicit reduction of invalid scalars" { |
| 622 | 623 | } |
| 623 | 624 | |
| 624 | 625 | test "subgroup check" { |
| 626 | const io = std.testing.io; | |
| 625 | 627 | for (0..100) |_| { |
| 626 | 628 | var p = Edwards25519.basePoint; |
| 627 | const s = Edwards25519.scalar.random(); | |
| 629 | const s = Edwards25519.scalar.random(io); | |
| 628 | 630 | p = try p.mulPublic(s); |
| 629 | 631 | try p.rejectUnexpectedSubgroup(); |
| 630 | 632 | } |
lib/std/crypto/25519/scalar.zig+7-6| ... | ... | @@ -101,8 +101,8 @@ pub fn sub(a: CompressedScalar, b: CompressedScalar) CompressedScalar { |
| 101 | 101 | } |
| 102 | 102 | |
| 103 | 103 | /// Return a random scalar < L |
| 104 | pub fn random() CompressedScalar { | |
| 105 | return Scalar.random().toBytes(); | |
| 104 | pub fn random(io: std.Io) CompressedScalar { | |
| 105 | return Scalar.random(io).toBytes(); | |
| 106 | 106 | } |
| 107 | 107 | |
| 108 | 108 | /// A scalar in unpacked representation |
| ... | ... | @@ -560,10 +560,10 @@ pub const Scalar = struct { |
| 560 | 560 | } |
| 561 | 561 | |
| 562 | 562 | /// Return a random scalar < L. |
| 563 | pub fn random() Scalar { | |
| 563 | pub fn random(io: std.Io) Scalar { | |
| 564 | 564 | var s: [64]u8 = undefined; |
| 565 | 565 | while (true) { |
| 566 | crypto.random.bytes(&s); | |
| 566 | io.random(&s); | |
| 567 | 567 | const n = Scalar.fromBytes64(s); |
| 568 | 568 | if (!n.isZero()) { |
| 569 | 569 | return n; |
| ... | ... | @@ -879,8 +879,9 @@ test "scalar field inversion" { |
| 879 | 879 | } |
| 880 | 880 | |
| 881 | 881 | test "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); | |
| 884 | 885 | try std.testing.expect(!mem.eql(u8, &s1, &s2)); |
| 885 | 886 | } |
| 886 | 887 |
lib/std/crypto/25519/x25519.zig+2-2| ... | ... | @@ -41,10 +41,10 @@ pub const X25519 = struct { |
| 41 | 41 | } |
| 42 | 42 | |
| 43 | 43 | /// Generate a new, random key pair. |
| 44 | pub fn generate() KeyPair { | |
| 44 | pub fn generate(io: std.Io) KeyPair { | |
| 45 | 45 | var random_seed: [seed_length]u8 = undefined; |
| 46 | 46 | while (true) { |
| 47 | crypto.random.bytes(&random_seed); | |
| 47 | io.random(&random_seed); | |
| 48 | 48 | return generateDeterministic(random_seed) catch { |
| 49 | 49 | @branchHint(.unlikely); |
| 50 | 50 | continue; |
lib/std/crypto/argon2.zig+1-1| ... | ... | @@ -533,7 +533,7 @@ const PhcFormatHasher = struct { |
| 533 | 533 | if (params.secret != null or params.ad != null) return HasherError.InvalidEncoding; |
| 534 | 534 | |
| 535 | 535 | var salt: [default_salt_len]u8 = undefined; |
| 536 | crypto.random.bytes(&salt); | |
| 536 | io.random(&salt); | |
| 537 | 537 | |
| 538 | 538 | var hash: [default_hash_len]u8 = undefined; |
| 539 | 539 | try kdf(allocator, &hash, password, &salt, params, mode, io); |
lib/std/crypto/bcrypt.zig+72-39| ... | ... | @@ -17,7 +17,7 @@ const HasherError = pwhash.HasherError; |
| 17 | 17 | const EncodingError = phc_format.Error; |
| 18 | 18 | const Error = pwhash.Error; |
| 19 | 19 | |
| 20 | const salt_length: usize = 16; | |
| 20 | pub const salt_length: usize = 16; | |
| 21 | 21 | const salt_str_length: usize = 22; |
| 22 | 22 | const ct_str_length: usize = 31; |
| 23 | 23 | const ct_length: usize = 24; |
| ... | ... | @@ -426,7 +426,7 @@ pub const Params = struct { |
| 426 | 426 | |
| 427 | 427 | fn bcryptWithTruncation( |
| 428 | 428 | password: []const u8, |
| 429 | salt: [salt_length]u8, | |
| 429 | salt: *const [salt_length]u8, | |
| 430 | 430 | params: Params, |
| 431 | 431 | ) [dk_length]u8 { |
| 432 | 432 | var state = State{}; |
| ... | ... | @@ -435,13 +435,13 @@ fn bcryptWithTruncation( |
| 435 | 435 | @memcpy(password_buf[0..trimmed_len], password[0..trimmed_len]); |
| 436 | 436 | password_buf[trimmed_len] = 0; |
| 437 | 437 | const passwordZ = password_buf[0 .. trimmed_len + 1]; |
| 438 | state.expand(salt[0..], passwordZ); | |
| 438 | state.expand(salt, passwordZ); | |
| 439 | 439 | |
| 440 | 440 | const rounds: u64 = @as(u64, 1) << params.rounds_log; |
| 441 | 441 | var k: u64 = 0; |
| 442 | 442 | while (k < rounds) : (k += 1) { |
| 443 | 443 | state.expand0(passwordZ); |
| 444 | state.expand0(salt[0..]); | |
| 444 | state.expand0(salt); | |
| 445 | 445 | } |
| 446 | 446 | crypto.secureZero(u8, &password_buf); |
| 447 | 447 | |
| ... | ... | @@ -467,7 +467,7 @@ fn bcryptWithTruncation( |
| 467 | 467 | /// For key derivation, use `bcrypt.pbkdf()` or `bcrypt.opensshKdf()` instead. |
| 468 | 468 | pub fn bcrypt( |
| 469 | 469 | password: []const u8, |
| 470 | salt: [salt_length]u8, | |
| 470 | salt: *const [salt_length]u8, | |
| 471 | 471 | params: Params, |
| 472 | 472 | ) [dk_length]u8 { |
| 473 | 473 | if (password.len <= 72 or params.silently_truncate_password) { |
| ... | ... | @@ -475,7 +475,7 @@ pub fn bcrypt( |
| 475 | 475 | } |
| 476 | 476 | |
| 477 | 477 | var pre_hash: [HmacSha512.mac_length]u8 = undefined; |
| 478 | HmacSha512.create(&pre_hash, password, &salt); | |
| 478 | HmacSha512.create(&pre_hash, password, salt); | |
| 479 | 479 | |
| 480 | 480 | const Encoder = crypt_format.Codec.Encoder; |
| 481 | 481 | var pre_hash_b64: [Encoder.calcSize(pre_hash.len)]u8 = undefined; |
| ... | ... | @@ -623,16 +623,16 @@ const crypt_format = struct { |
| 623 | 623 | |
| 624 | 624 | fn strHashInternal( |
| 625 | 625 | password: []const u8, |
| 626 | salt: [salt_length]u8, | |
| 626 | salt: *const [salt_length]u8, | |
| 627 | 627 | params: Params, |
| 628 | 628 | ) [hash_length]u8 { |
| 629 | 629 | var dk = bcrypt(password, salt, params); |
| 630 | 630 | |
| 631 | 631 | var salt_str: [salt_str_length]u8 = undefined; |
| 632 | _ = Codec.Encoder.encode(salt_str[0..], salt[0..]); | |
| 632 | _ = Codec.Encoder.encode(&salt_str, salt); | |
| 633 | 633 | |
| 634 | 634 | 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..]); | |
| 636 | 636 | |
| 637 | 637 | var s_buf: [hash_length]u8 = undefined; |
| 638 | 638 | const s = fmt.bufPrint( |
| ... | ... | @@ -657,21 +657,20 @@ const PhcFormatHasher = struct { |
| 657 | 657 | hash: BinValue(dk_length), |
| 658 | 658 | }; |
| 659 | 659 | |
| 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. | |
| 661 | 661 | fn create( |
| 662 | 662 | password: []const u8, |
| 663 | 663 | params: Params, |
| 664 | 664 | buf: []u8, |
| 665 | /// Filled with cryptographically secure entropy. | |
| 666 | salt: *const [salt_length]u8, | |
| 665 | 667 | ) HasherError![]const u8 { |
| 666 | var salt: [salt_length]u8 = undefined; | |
| 667 | crypto.random.bytes(&salt); | |
| 668 | ||
| 669 | 668 | const hash = bcrypt(password, salt, params); |
| 670 | 669 | |
| 671 | 670 | return phc_format.serialize(HashResult{ |
| 672 | 671 | .alg_id = alg_id, |
| 673 | 672 | .r = params.rounds_log, |
| 674 | .salt = try BinValue(salt_length).fromSlice(&salt), | |
| 673 | .salt = try BinValue(salt_length).fromSlice(salt), | |
| 675 | 674 | .hash = try BinValue(dk_length).fromSlice(&hash), |
| 676 | 675 | }, buf); |
| 677 | 676 | } |
| ... | ... | @@ -688,11 +687,11 @@ const PhcFormatHasher = struct { |
| 688 | 687 | if (hash_result.salt.len != salt_length or hash_result.hash.len != dk_length) |
| 689 | 688 | return HasherError.InvalidEncoding; |
| 690 | 689 | |
| 691 | const params = Params{ | |
| 690 | const params: Params = .{ | |
| 692 | 691 | .rounds_log = hash_result.r, |
| 693 | 692 | .silently_truncate_password = silently_truncate_password, |
| 694 | 693 | }; |
| 695 | const hash = bcrypt(password, hash_result.salt.buf, params); | |
| 694 | const hash = bcrypt(password, &hash_result.salt.buf, params); | |
| 696 | 695 | const expected_hash = hash_result.hash.constSlice(); |
| 697 | 696 | |
| 698 | 697 | if (!mem.eql(u8, &hash, expected_hash)) return HasherError.PasswordVerificationFailed; |
| ... | ... | @@ -709,12 +708,11 @@ const CryptFormatHasher = struct { |
| 709 | 708 | password: []const u8, |
| 710 | 709 | params: Params, |
| 711 | 710 | buf: []u8, |
| 711 | /// Filled with cryptographically secure entropy. | |
| 712 | salt: *const [salt_length]u8, | |
| 712 | 713 | ) HasherError![]const u8 { |
| 713 | 714 | if (buf.len < pwhash_str_length) return HasherError.NoSpaceLeft; |
| 714 | 715 | |
| 715 | var salt: [salt_length]u8 = undefined; | |
| 716 | crypto.random.bytes(&salt); | |
| 717 | ||
| 718 | 716 | const hash = crypt_format.strHashInternal(password, salt, params); |
| 719 | 717 | @memcpy(buf[0..hash.len], &hash); |
| 720 | 718 | |
| ... | ... | @@ -736,9 +734,9 @@ const CryptFormatHasher = struct { |
| 736 | 734 | |
| 737 | 735 | const salt_str = str[7..][0..salt_str_length]; |
| 738 | 736 | 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; | |
| 740 | 738 | |
| 741 | const wanted_s = crypt_format.strHashInternal(password, salt, .{ | |
| 739 | const wanted_s = crypt_format.strHashInternal(password, &salt, .{ | |
| 742 | 740 | .rounds_log = rounds_log, |
| 743 | 741 | .silently_truncate_password = silently_truncate_password, |
| 744 | 742 | }); |
| ... | ... | @@ -756,21 +754,28 @@ pub const HashOptions = struct { |
| 756 | 754 | encoding: pwhash.Encoding, |
| 757 | 755 | }; |
| 758 | 756 | |
| 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. | |
| 761 | 762 | /// |
| 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. | |
| 763 | 765 | /// |
| 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`. | |
| 766 | 769 | pub fn strHash( |
| 767 | 770 | password: []const u8, |
| 768 | 771 | options: HashOptions, |
| 769 | 772 | out: []u8, |
| 773 | /// Filled with cryptographically secure entropy. | |
| 774 | salt: *const [salt_length]u8, | |
| 770 | 775 | ) Error![]const u8 { |
| 771 | 776 | 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), | |
| 774 | 779 | } |
| 775 | 780 | } |
| 776 | 781 | |
| ... | ... | @@ -796,8 +801,9 @@ pub fn strVerify( |
| 796 | 801 | } |
| 797 | 802 | |
| 798 | 803 | test "bcrypt codec" { |
| 804 | const io = testing.io; | |
| 799 | 805 | var salt: [salt_length]u8 = undefined; |
| 800 | crypto.random.bytes(&salt); | |
| 806 | io.random(&salt); | |
| 801 | 807 | var salt_str: [salt_str_length]u8 = undefined; |
| 802 | 808 | _ = crypt_format.Codec.Encoder.encode(salt_str[0..], salt[0..]); |
| 803 | 809 | var salt2: [salt_length]u8 = undefined; |
| ... | ... | @@ -806,14 +812,20 @@ test "bcrypt codec" { |
| 806 | 812 | } |
| 807 | 813 | |
| 808 | 814 | test "bcrypt crypt format" { |
| 809 | var hash_options = HashOptions{ | |
| 815 | const io = testing.io; | |
| 816 | ||
| 817 | var hash_options: HashOptions = .{ | |
| 810 | 818 | .params = .{ .rounds_log = 5, .silently_truncate_password = false }, |
| 811 | 819 | .encoding = .crypt, |
| 812 | 820 | }; |
| 813 | var verify_options = VerifyOptions{ .silently_truncate_password = false }; | |
| 821 | var verify_options: VerifyOptions = .{ .silently_truncate_password = false }; | |
| 814 | 822 | |
| 815 | 823 | 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 | }; | |
| 817 | 829 | |
| 818 | 830 | try testing.expect(mem.startsWith(u8, s, crypt_format.prefix)); |
| 819 | 831 | try strVerify(s, "password", verify_options); |
| ... | ... | @@ -823,7 +835,11 @@ test "bcrypt crypt format" { |
| 823 | 835 | ); |
| 824 | 836 | |
| 825 | 837 | 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 | }; | |
| 827 | 843 | |
| 828 | 844 | try testing.expect(mem.startsWith(u8, long_s, crypt_format.prefix)); |
| 829 | 845 | try strVerify(long_s, "password" ** 100, verify_options); |
| ... | ... | @@ -834,7 +850,11 @@ test "bcrypt crypt format" { |
| 834 | 850 | |
| 835 | 851 | hash_options.params.silently_truncate_password = true; |
| 836 | 852 | 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 | }; | |
| 838 | 858 | try strVerify(long_s, "password" ** 101, verify_options); |
| 839 | 859 | |
| 840 | 860 | try strVerify( |
| ... | ... | @@ -845,15 +865,20 @@ test "bcrypt crypt format" { |
| 845 | 865 | } |
| 846 | 866 | |
| 847 | 867 | test "bcrypt phc format" { |
| 848 | var hash_options = HashOptions{ | |
| 868 | const io = testing.io; | |
| 869 | var hash_options: HashOptions = .{ | |
| 849 | 870 | .params = .{ .rounds_log = 5, .silently_truncate_password = false }, |
| 850 | 871 | .encoding = .phc, |
| 851 | 872 | }; |
| 852 | var verify_options = VerifyOptions{ .silently_truncate_password = false }; | |
| 873 | var verify_options: VerifyOptions = .{ .silently_truncate_password = false }; | |
| 853 | 874 | const prefix = "$bcrypt$"; |
| 854 | 875 | |
| 855 | 876 | 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 | }; | |
| 857 | 882 | |
| 858 | 883 | try testing.expect(mem.startsWith(u8, s, prefix)); |
| 859 | 884 | try strVerify(s, "password", verify_options); |
| ... | ... | @@ -863,7 +888,11 @@ test "bcrypt phc format" { |
| 863 | 888 | ); |
| 864 | 889 | |
| 865 | 890 | 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 | }; | |
| 867 | 896 | |
| 868 | 897 | try testing.expect(mem.startsWith(u8, long_s, prefix)); |
| 869 | 898 | try strVerify(long_s, "password" ** 100, verify_options); |
| ... | ... | @@ -874,7 +903,11 @@ test "bcrypt phc format" { |
| 874 | 903 | |
| 875 | 904 | hash_options.params.silently_truncate_password = true; |
| 876 | 905 | 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 | }; | |
| 878 | 911 | try strVerify(long_s, "password" ** 101, verify_options); |
| 879 | 912 | |
| 880 | 913 | try strVerify( |
lib/std/crypto/ecdsa.zig+17-11| ... | ... | @@ -323,10 +323,10 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type { |
| 323 | 323 | } |
| 324 | 324 | |
| 325 | 325 | /// Generate a new, random key pair. |
| 326 | pub fn generate() KeyPair { | |
| 326 | pub fn generate(io: std.Io) KeyPair { | |
| 327 | 327 | var random_seed: [seed_length]u8 = undefined; |
| 328 | 328 | while (true) { |
| 329 | crypto.random.bytes(&random_seed); | |
| 329 | io.random(&random_seed); | |
| 330 | 330 | return generateDeterministic(random_seed) catch { |
| 331 | 331 | @branchHint(.unlikely); |
| 332 | 332 | continue; |
| ... | ... | @@ -417,12 +417,13 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type { |
| 417 | 417 | test "Basic operations over EcdsaP384Sha384" { |
| 418 | 418 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 419 | 419 | |
| 420 | const io = testing.io; | |
| 420 | 421 | const Scheme = EcdsaP384Sha384; |
| 421 | const kp = Scheme.KeyPair.generate(); | |
| 422 | const kp = Scheme.KeyPair.generate(io); | |
| 422 | 423 | const msg = "test"; |
| 423 | 424 | |
| 424 | 425 | var noise: [Scheme.noise_length]u8 = undefined; |
| 425 | crypto.random.bytes(&noise); | |
| 426 | io.random(&noise); | |
| 426 | 427 | const sig = try kp.sign(msg, noise); |
| 427 | 428 | try sig.verify(msg, kp.public_key); |
| 428 | 429 | |
| ... | ... | @@ -433,12 +434,13 @@ test "Basic operations over EcdsaP384Sha384" { |
| 433 | 434 | test "Basic operations over Secp256k1" { |
| 434 | 435 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 435 | 436 | |
| 437 | const io = testing.io; | |
| 436 | 438 | const Scheme = EcdsaSecp256k1Sha256oSha256; |
| 437 | const kp = Scheme.KeyPair.generate(); | |
| 439 | const kp = Scheme.KeyPair.generate(io); | |
| 438 | 440 | const msg = "test"; |
| 439 | 441 | |
| 440 | 442 | var noise: [Scheme.noise_length]u8 = undefined; |
| 441 | crypto.random.bytes(&noise); | |
| 443 | io.random(&noise); | |
| 442 | 444 | const sig = try kp.sign(msg, noise); |
| 443 | 445 | try sig.verify(msg, kp.public_key); |
| 444 | 446 | |
| ... | ... | @@ -449,12 +451,13 @@ test "Basic operations over Secp256k1" { |
| 449 | 451 | test "Basic operations over EcdsaP384Sha256" { |
| 450 | 452 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 451 | 453 | |
| 454 | const io = testing.io; | |
| 452 | 455 | const Scheme = Ecdsa(crypto.ecc.P384, crypto.hash.sha2.Sha256); |
| 453 | const kp = Scheme.KeyPair.generate(); | |
| 456 | const kp = Scheme.KeyPair.generate(io); | |
| 454 | 457 | const msg = "test"; |
| 455 | 458 | |
| 456 | 459 | var noise: [Scheme.noise_length]u8 = undefined; |
| 457 | crypto.random.bytes(&noise); | |
| 460 | io.random(&noise); | |
| 458 | 461 | const sig = try kp.sign(msg, noise); |
| 459 | 462 | try sig.verify(msg, kp.public_key); |
| 460 | 463 | |
| ... | ... | @@ -502,8 +505,10 @@ test "Verifying a existing signature with EcdsaP384Sha256" { |
| 502 | 505 | test "Prehashed message operations" { |
| 503 | 506 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 504 | 507 | |
| 508 | const io = testing.io; | |
| 509 | ||
| 505 | 510 | const Scheme = EcdsaP256Sha256; |
| 506 | const kp = Scheme.KeyPair.generate(); | |
| 511 | const kp = Scheme.KeyPair.generate(io); | |
| 507 | 512 | const msg = "test message for prehashed signing"; |
| 508 | 513 | |
| 509 | 514 | const Hash = crypto.hash.sha2.Sha256; |
| ... | ... | @@ -518,7 +523,7 @@ test "Prehashed message operations" { |
| 518 | 523 | try testing.expectError(error.SignatureVerificationFailed, sig.verifyPrehashed(bad_hash, kp.public_key)); |
| 519 | 524 | |
| 520 | 525 | var noise: [Scheme.noise_length]u8 = undefined; |
| 521 | crypto.random.bytes(&noise); | |
| 526 | io.random(&noise); | |
| 522 | 527 | const sig_with_noise = try kp.signPrehashed(msg_hash, noise); |
| 523 | 528 | try sig_with_noise.verifyPrehashed(msg_hash, kp.public_key); |
| 524 | 529 | |
| ... | ... | @@ -1628,8 +1633,9 @@ fn tvTry(comptime Scheme: type, vector: TestVector) !void { |
| 1628 | 1633 | test "Sec1 encoding/decoding" { |
| 1629 | 1634 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 1630 | 1635 | |
| 1636 | const io = testing.io; | |
| 1631 | 1637 | const Scheme = EcdsaP384Sha384; |
| 1632 | const kp = Scheme.KeyPair.generate(); | |
| 1638 | const kp = Scheme.KeyPair.generate(io); | |
| 1633 | 1639 | const pk = kp.public_key; |
| 1634 | 1640 | const pk_compressed_sec1 = pk.toCompressedSec1(); |
| 1635 | 1641 | 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 { |
| 174 | 174 | return .{ .bytes = buf.* }; |
| 175 | 175 | } |
| 176 | 176 | |
| 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 { | |
| 185 | 182 | 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 | } | |
| 187 | 189 | |
| 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; | |
| 191 | 198 | |
| 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) | |
| 193 | 205 | 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); | |
| 204 | 207 | } |
| 205 | 208 | } 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]); | |
| 210 | 211 | } |
| 211 | 212 | |
| 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); | |
| 214 | 227 | const ct_t_point = try params.Group.mulBase(sk_e); |
| 215 | 228 | const ct_t = if (is_nist_curve) params.Group.encodePoint(ct_t_point) else ct_t_point; |
| 216 | 229 | |
| ... | ... | @@ -280,9 +293,9 @@ pub fn HybridKem(comptime params: Params) type { |
| 280 | 293 | } |
| 281 | 294 | |
| 282 | 295 | /// Generates a new random key pair. |
| 283 | pub fn generate() !KeyPair { | |
| 296 | pub fn generate(io: std.Io) !KeyPair { | |
| 284 | 297 | var seed: [params.Nseed]u8 = undefined; |
| 285 | crypto.random.bytes(&seed); | |
| 298 | io.random(&seed); | |
| 286 | 299 | return generateDeterministic(seed); |
| 287 | 300 | } |
| 288 | 301 | }; |
| ... | ... | @@ -386,7 +399,7 @@ test "MLKEM768-X25519 basic round trip" { |
| 386 | 399 | var enc_seed: [64]u8 = undefined; |
| 387 | 400 | @memset(&enc_seed, 0x43); |
| 388 | 401 | |
| 389 | const encap_result = try kp.public_key.encaps(&enc_seed); | |
| 402 | const encap_result = try kp.public_key.encapsDeterministic(&enc_seed); | |
| 390 | 403 | const ss_decap = try kp.secret_key.decaps(&encap_result.ciphertext); |
| 391 | 404 | |
| 392 | 405 | try testing.expectEqualSlices(u8, &encap_result.shared_secret, &ss_decap); |
| ... | ... | @@ -408,7 +421,7 @@ test "MLKEM768-X25519 test vector 0" { |
| 408 | 421 | const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed); |
| 409 | 422 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 410 | 423 | |
| 411 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 424 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 412 | 425 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 413 | 426 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 414 | 427 | |
| ... | ... | @@ -432,7 +445,7 @@ test "MLKEM768-X25519 test vector 1" { |
| 432 | 445 | const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed); |
| 433 | 446 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 434 | 447 | |
| 435 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 448 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 436 | 449 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 437 | 450 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 438 | 451 | |
| ... | ... | @@ -456,7 +469,7 @@ test "MLKEM768-X25519 test vector 2" { |
| 456 | 469 | const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed); |
| 457 | 470 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 458 | 471 | |
| 459 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 472 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 460 | 473 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 461 | 474 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 462 | 475 | |
| ... | ... | @@ -480,7 +493,7 @@ test "MLKEM768-X25519 test vector 3" { |
| 480 | 493 | const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed); |
| 481 | 494 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 482 | 495 | |
| 483 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 496 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 484 | 497 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 485 | 498 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 486 | 499 | |
| ... | ... | @@ -504,7 +517,7 @@ test "MLKEM768-X25519 test vector 4" { |
| 504 | 517 | const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed); |
| 505 | 518 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 506 | 519 | |
| 507 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 520 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 508 | 521 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 509 | 522 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 510 | 523 | |
| ... | ... | @@ -528,7 +541,7 @@ test "MLKEM768-X25519 test vector 5" { |
| 528 | 541 | const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed); |
| 529 | 542 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 530 | 543 | |
| 531 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 544 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 532 | 545 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 533 | 546 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 534 | 547 | |
| ... | ... | @@ -552,7 +565,7 @@ test "MLKEM768-X25519 test vector 6" { |
| 552 | 565 | const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed); |
| 553 | 566 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 554 | 567 | |
| 555 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 568 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 556 | 569 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 557 | 570 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 558 | 571 | |
| ... | ... | @@ -576,7 +589,7 @@ test "MLKEM768-X25519 test vector 7" { |
| 576 | 589 | const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed); |
| 577 | 590 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 578 | 591 | |
| 579 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 592 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 580 | 593 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 581 | 594 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 582 | 595 | |
| ... | ... | @@ -600,7 +613,7 @@ test "MLKEM768-X25519 test vector 8" { |
| 600 | 613 | const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed); |
| 601 | 614 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 602 | 615 | |
| 603 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 616 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 604 | 617 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 605 | 618 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 606 | 619 | |
| ... | ... | @@ -624,7 +637,7 @@ test "MLKEM768-X25519 test vector 9" { |
| 624 | 637 | const kp = try MlKem768X25519.KeyPair.generateDeterministic(seed); |
| 625 | 638 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 626 | 639 | |
| 627 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 640 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 628 | 641 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 629 | 642 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 630 | 643 | |
| ... | ... | @@ -648,7 +661,7 @@ test "MLKEM768-P256 test vector 0" { |
| 648 | 661 | const kp = try MlKem768P256.KeyPair.generateDeterministic(seed); |
| 649 | 662 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 650 | 663 | |
| 651 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 664 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 652 | 665 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 653 | 666 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 654 | 667 | |
| ... | ... | @@ -672,7 +685,7 @@ test "MLKEM768-P256 test vector 1" { |
| 672 | 685 | const kp = try MlKem768P256.KeyPair.generateDeterministic(seed); |
| 673 | 686 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 674 | 687 | |
| 675 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 688 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 676 | 689 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 677 | 690 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 678 | 691 | |
| ... | ... | @@ -696,7 +709,7 @@ test "MLKEM768-P256 test vector 2" { |
| 696 | 709 | const kp = try MlKem768P256.KeyPair.generateDeterministic(seed); |
| 697 | 710 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 698 | 711 | |
| 699 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 712 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 700 | 713 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 701 | 714 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 702 | 715 | |
| ... | ... | @@ -720,7 +733,7 @@ test "MLKEM768-P256 test vector 3" { |
| 720 | 733 | const kp = try MlKem768P256.KeyPair.generateDeterministic(seed); |
| 721 | 734 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 722 | 735 | |
| 723 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 736 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 724 | 737 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 725 | 738 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 726 | 739 | |
| ... | ... | @@ -744,7 +757,7 @@ test "MLKEM768-P256 test vector 4" { |
| 744 | 757 | const kp = try MlKem768P256.KeyPair.generateDeterministic(seed); |
| 745 | 758 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 746 | 759 | |
| 747 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 760 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 748 | 761 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 749 | 762 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 750 | 763 | |
| ... | ... | @@ -768,7 +781,7 @@ test "MLKEM768-P256 test vector 5" { |
| 768 | 781 | const kp = try MlKem768P256.KeyPair.generateDeterministic(seed); |
| 769 | 782 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 770 | 783 | |
| 771 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 784 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 772 | 785 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 773 | 786 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 774 | 787 | |
| ... | ... | @@ -792,7 +805,7 @@ test "MLKEM768-P256 test vector 6" { |
| 792 | 805 | const kp = try MlKem768P256.KeyPair.generateDeterministic(seed); |
| 793 | 806 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 794 | 807 | |
| 795 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 808 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 796 | 809 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 797 | 810 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 798 | 811 | |
| ... | ... | @@ -816,7 +829,7 @@ test "MLKEM768-P256 test vector 7" { |
| 816 | 829 | const kp = try MlKem768P256.KeyPair.generateDeterministic(seed); |
| 817 | 830 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 818 | 831 | |
| 819 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 832 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 820 | 833 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 821 | 834 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 822 | 835 | |
| ... | ... | @@ -840,7 +853,7 @@ test "MLKEM768-P256 test vector 8" { |
| 840 | 853 | const kp = try MlKem768P256.KeyPair.generateDeterministic(seed); |
| 841 | 854 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 842 | 855 | |
| 843 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 856 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 844 | 857 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 845 | 858 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 846 | 859 | |
| ... | ... | @@ -864,7 +877,7 @@ test "MLKEM768-P256 test vector 9" { |
| 864 | 877 | const kp = try MlKem768P256.KeyPair.generateDeterministic(seed); |
| 865 | 878 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 866 | 879 | |
| 867 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 880 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 868 | 881 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 869 | 882 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 870 | 883 | |
| ... | ... | @@ -888,7 +901,7 @@ test "MLKEM1024-P384 test vector 0" { |
| 888 | 901 | const kp = try MlKem1024P384.KeyPair.generateDeterministic(seed); |
| 889 | 902 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 890 | 903 | |
| 891 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 904 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 892 | 905 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 893 | 906 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 894 | 907 | |
| ... | ... | @@ -912,7 +925,7 @@ test "MLKEM1024-P384 test vector 1" { |
| 912 | 925 | const kp = try MlKem1024P384.KeyPair.generateDeterministic(seed); |
| 913 | 926 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 914 | 927 | |
| 915 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 928 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 916 | 929 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 917 | 930 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 918 | 931 | |
| ... | ... | @@ -936,7 +949,7 @@ test "MLKEM1024-P384 test vector 2" { |
| 936 | 949 | const kp = try MlKem1024P384.KeyPair.generateDeterministic(seed); |
| 937 | 950 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 938 | 951 | |
| 939 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 952 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 940 | 953 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 941 | 954 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 942 | 955 | |
| ... | ... | @@ -960,7 +973,7 @@ test "MLKEM1024-P384 test vector 3" { |
| 960 | 973 | const kp = try MlKem1024P384.KeyPair.generateDeterministic(seed); |
| 961 | 974 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 962 | 975 | |
| 963 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 976 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 964 | 977 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 965 | 978 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 966 | 979 | |
| ... | ... | @@ -984,7 +997,7 @@ test "MLKEM1024-P384 test vector 4" { |
| 984 | 997 | const kp = try MlKem1024P384.KeyPair.generateDeterministic(seed); |
| 985 | 998 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 986 | 999 | |
| 987 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 1000 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 988 | 1001 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 989 | 1002 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 990 | 1003 | |
| ... | ... | @@ -1008,7 +1021,7 @@ test "MLKEM1024-P384 test vector 5" { |
| 1008 | 1021 | const kp = try MlKem1024P384.KeyPair.generateDeterministic(seed); |
| 1009 | 1022 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 1010 | 1023 | |
| 1011 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 1024 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 1012 | 1025 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 1013 | 1026 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 1014 | 1027 | |
| ... | ... | @@ -1032,7 +1045,7 @@ test "MLKEM1024-P384 test vector 6" { |
| 1032 | 1045 | const kp = try MlKem1024P384.KeyPair.generateDeterministic(seed); |
| 1033 | 1046 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 1034 | 1047 | |
| 1035 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 1048 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 1036 | 1049 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 1037 | 1050 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 1038 | 1051 | |
| ... | ... | @@ -1056,7 +1069,7 @@ test "MLKEM1024-P384 test vector 7" { |
| 1056 | 1069 | const kp = try MlKem1024P384.KeyPair.generateDeterministic(seed); |
| 1057 | 1070 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 1058 | 1071 | |
| 1059 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 1072 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 1060 | 1073 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 1061 | 1074 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 1062 | 1075 | |
| ... | ... | @@ -1080,7 +1093,7 @@ test "MLKEM1024-P384 test vector 8" { |
| 1080 | 1093 | const kp = try MlKem1024P384.KeyPair.generateDeterministic(seed); |
| 1081 | 1094 | try testing.expectEqualSlices(u8, &expected_ek, &kp.public_key.toBytes()); |
| 1082 | 1095 | |
| 1083 | const enc_result = try kp.public_key.encaps(&randomness); | |
| 1096 | const enc_result = try kp.public_key.encapsDeterministic(&randomness); | |
| 1084 | 1097 | try testing.expectEqualSlices(u8, &expected_ct, &enc_result.ciphertext); |
| 1085 | 1098 | try testing.expectEqualSlices(u8, &expected_ss, &enc_result.shared_secret); |
| 1086 | 1099 |
lib/std/crypto/ml_dsa.zig+10-9| ... | ... | @@ -2019,12 +2019,9 @@ fn MLDSAImpl(comptime p: Params) type { |
| 2019 | 2019 | secret_key: SecretKey, |
| 2020 | 2020 | |
| 2021 | 2021 | /// 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 { | |
| 2026 | 2023 | var seed: [Self.seed_length]u8 = undefined; |
| 2027 | crypto.random.bytes(&seed); | |
| 2024 | io.random(&seed); | |
| 2028 | 2025 | return generateDeterministic(seed) catch unreachable; |
| 2029 | 2026 | } |
| 2030 | 2027 | |
| ... | ... | @@ -3198,8 +3195,9 @@ test "ML-DSA-87 KAT test vector 0" { |
| 3198 | 3195 | } |
| 3199 | 3196 | |
| 3200 | 3197 | test "KeyPair API - generate and sign" { |
| 3198 | const io = std.testing.io; | |
| 3201 | 3199 | // Test the new KeyPair API with random generation |
| 3202 | const kp = MLDSA44.KeyPair.generate(); | |
| 3200 | const kp = MLDSA44.KeyPair.generate(io); | |
| 3203 | 3201 | const msg = "Test message for KeyPair API"; |
| 3204 | 3202 | |
| 3205 | 3203 | // Sign with deterministic mode (no noise) |
| ... | ... | @@ -3222,8 +3220,9 @@ test "KeyPair API - generateDeterministic" { |
| 3222 | 3220 | } |
| 3223 | 3221 | |
| 3224 | 3222 | test "KeyPair API - fromSecretKey" { |
| 3223 | const io = std.testing.io; | |
| 3225 | 3224 | // Generate a key pair |
| 3226 | const kp1 = MLDSA44.KeyPair.generate(); | |
| 3225 | const kp1 = MLDSA44.KeyPair.generate(io); | |
| 3227 | 3226 | |
| 3228 | 3227 | // Derive public key from secret key |
| 3229 | 3228 | const kp2 = try MLDSA44.KeyPair.fromSecretKey(kp1.secret_key); |
| ... | ... | @@ -3235,8 +3234,9 @@ test "KeyPair API - fromSecretKey" { |
| 3235 | 3234 | } |
| 3236 | 3235 | |
| 3237 | 3236 | test "Signature verification with noise" { |
| 3237 | const io = std.testing.io; | |
| 3238 | 3238 | // Test signing with randomness (hedged signatures) |
| 3239 | const kp = MLDSA65.KeyPair.generate(); | |
| 3239 | const kp = MLDSA65.KeyPair.generate(io); | |
| 3240 | 3240 | const msg = "Message to be signed with randomness"; |
| 3241 | 3241 | |
| 3242 | 3242 | // Create some noise |
| ... | ... | @@ -3250,8 +3250,9 @@ test "Signature verification with noise" { |
| 3250 | 3250 | } |
| 3251 | 3251 | |
| 3252 | 3252 | test "Signature verification failure" { |
| 3253 | const io = std.testing.io; | |
| 3253 | 3254 | // Test that invalid signatures are rejected |
| 3254 | const kp = MLDSA44.KeyPair.generate(); | |
| 3255 | const kp = MLDSA44.KeyPair.generate(io); | |
| 3255 | 3256 | const msg = "Original message"; |
| 3256 | 3257 | const sig = try kp.sign(msg, null); |
| 3257 | 3258 |
lib/std/crypto/ml_kem.zig+29-20| ... | ... | @@ -244,32 +244,41 @@ fn Kyber(comptime p: Params) type { |
| 244 | 244 | /// Size of a serialized representation of the key, in bytes. |
| 245 | 245 | pub const encoded_length = InnerPk.encoded_length; |
| 246 | 246 | |
| 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 { | |
| 251 | 252 | var m: [inner_plaintext_length]u8 = undefined; |
| 253 | io.random(&m); | |
| 254 | return encapsInner(pk, &m); | |
| 255 | } | |
| 252 | 256 | |
| 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); | |
| 260 | 265 | } else { |
| 261 | crypto.random.bytes(&m); | |
| 266 | // m = H(seed) | |
| 267 | sha3.Sha3_256.hash(seed, &m, .{}); | |
| 262 | 268 | } |
| 269 | return encapsInner(pk, &m); | |
| 270 | } | |
| 263 | 271 | |
| 272 | fn encapsInner(pk: PublicKey, m: *[inner_plaintext_length]u8) EncapsulatedSecret { | |
| 264 | 273 | // (K', r) = G(m ‖ H(pk)) |
| 265 | 274 | var kr: [inner_plaintext_length + h_length]u8 = undefined; |
| 266 | 275 | var g = sha3.Sha3_512.init(.{}); |
| 267 | g.update(&m); | |
| 276 | g.update(m); | |
| 268 | 277 | g.update(&pk.hpk); |
| 269 | 278 | g.final(&kr); |
| 270 | 279 | |
| 271 | 280 | // 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]); | |
| 273 | 282 | |
| 274 | 283 | if (p.ml_kem) { |
| 275 | 284 | return EncapsulatedSecret{ |
| ... | ... | @@ -398,10 +407,10 @@ fn Kyber(comptime p: Params) type { |
| 398 | 407 | } |
| 399 | 408 | |
| 400 | 409 | /// Generate a new, random key pair. |
| 401 | pub fn generate() KeyPair { | |
| 410 | pub fn generate(io: std.Io) KeyPair { | |
| 402 | 411 | var random_seed: [seed_length]u8 = undefined; |
| 403 | 412 | while (true) { |
| 404 | crypto.random.bytes(&random_seed); | |
| 413 | io.random(&random_seed); | |
| 405 | 414 | return generateDeterministic(random_seed) catch { |
| 406 | 415 | @branchHint(.unlikely); |
| 407 | 416 | continue; |
| ... | ... | @@ -1634,15 +1643,15 @@ test "Test happy flow" { |
| 1634 | 1643 | } |
| 1635 | 1644 | inline for (modes) |mode| { |
| 1636 | 1645 | for (0..10) |i| { |
| 1637 | seed[0] = @as(u8, @intCast(i)); | |
| 1646 | seed[0] = @intCast(i); | |
| 1638 | 1647 | const kp = try mode.KeyPair.generateDeterministic(seed); |
| 1639 | 1648 | const sk = try mode.SecretKey.fromBytes(&kp.secret_key.toBytes()); |
| 1640 | 1649 | try testing.expectEqual(sk, kp.secret_key); |
| 1641 | 1650 | const pk = try mode.PublicKey.fromBytes(&kp.public_key.toBytes()); |
| 1642 | 1651 | try testing.expectEqual(pk, kp.public_key); |
| 1643 | 1652 | 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]); | |
| 1646 | 1655 | try testing.expectEqual(e.shared_secret, try sk.decaps(&e.ciphertext)); |
| 1647 | 1656 | } |
| 1648 | 1657 | } |
| ... | ... | @@ -1695,7 +1704,7 @@ fn testNistKat(mode: type, hash: []const u8) !void { |
| 1695 | 1704 | g2.fill(kseed[32..64]); |
| 1696 | 1705 | g2.fill(&eseed); |
| 1697 | 1706 | const kp = try mode.KeyPair.generateDeterministic(kseed); |
| 1698 | const e = kp.public_key.encaps(eseed); | |
| 1707 | const e = kp.public_key.encapsDeterministic(&eseed); | |
| 1699 | 1708 | const ss2 = try kp.secret_key.decaps(&e.ciphertext); |
| 1700 | 1709 | try testing.expectEqual(ss2, e.shared_secret); |
| 1701 | 1710 | 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 { |
| 122 | 122 | } |
| 123 | 123 | |
| 124 | 124 | /// 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); | |
| 127 | 127 | return basePoint.mul(n, .little) catch unreachable; |
| 128 | 128 | } |
| 129 | 129 |
lib/std/crypto/pcurves/p256/scalar.zig+4-4| ... | ... | @@ -68,8 +68,8 @@ pub fn sub(a: CompressedScalar, b: CompressedScalar, endian: std.builtin.Endian) |
| 68 | 68 | } |
| 69 | 69 | |
| 70 | 70 | /// Return a random scalar |
| 71 | pub fn random(endian: std.builtin.Endian) CompressedScalar { | |
| 72 | return Scalar.random().toBytes(endian); | |
| 71 | pub fn random(io: std.Io, endian: std.builtin.Endian) CompressedScalar { | |
| 72 | return Scalar.random(io).toBytes(endian); | |
| 73 | 73 | } |
| 74 | 74 | |
| 75 | 75 | /// A scalar in unpacked representation. |
| ... | ... | @@ -170,10 +170,10 @@ pub const Scalar = struct { |
| 170 | 170 | } |
| 171 | 171 | |
| 172 | 172 | /// Return a random scalar < L. |
| 173 | pub fn random() Scalar { | |
| 173 | pub fn random(io: std.Io) Scalar { | |
| 174 | 174 | var s: [48]u8 = undefined; |
| 175 | 175 | while (true) { |
| 176 | crypto.random.bytes(&s); | |
| 176 | io.random(&s); | |
| 177 | 177 | const n = Scalar.fromBytes48(s, .little); |
| 178 | 178 | if (!n.isZero()) { |
| 179 | 179 | return n; |
lib/std/crypto/pcurves/p384.zig+2-2| ... | ... | @@ -122,8 +122,8 @@ pub const P384 = struct { |
| 122 | 122 | } |
| 123 | 123 | |
| 124 | 124 | /// 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); | |
| 127 | 127 | return basePoint.mul(n, .little) catch unreachable; |
| 128 | 128 | } |
| 129 | 129 |
lib/std/crypto/pcurves/p384/scalar.zig+4-4| ... | ... | @@ -63,8 +63,8 @@ pub fn sub(a: CompressedScalar, b: CompressedScalar, endian: std.builtin.Endian) |
| 63 | 63 | } |
| 64 | 64 | |
| 65 | 65 | /// Return a random scalar |
| 66 | pub fn random(endian: std.builtin.Endian) CompressedScalar { | |
| 67 | return Scalar.random().toBytes(endian); | |
| 66 | pub fn random(io: std.Io, endian: std.builtin.Endian) CompressedScalar { | |
| 67 | return Scalar.random(io).toBytes(endian); | |
| 68 | 68 | } |
| 69 | 69 | |
| 70 | 70 | /// A scalar in unpacked representation. |
| ... | ... | @@ -159,10 +159,10 @@ pub const Scalar = struct { |
| 159 | 159 | } |
| 160 | 160 | |
| 161 | 161 | /// Return a random scalar < L. |
| 162 | pub fn random() Scalar { | |
| 162 | pub fn random(io: std.Io) Scalar { | |
| 163 | 163 | var s: [64]u8 = undefined; |
| 164 | 164 | while (true) { |
| 165 | crypto.random.bytes(&s); | |
| 165 | io.random(&s); | |
| 166 | 166 | const n = Scalar.fromBytes64(s, .little); |
| 167 | 167 | if (!n.isZero()) { |
| 168 | 168 | return n; |
lib/std/crypto/pcurves/secp256k1.zig+2-2| ... | ... | @@ -175,8 +175,8 @@ pub const Secp256k1 = struct { |
| 175 | 175 | } |
| 176 | 176 | |
| 177 | 177 | /// 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); | |
| 180 | 180 | return basePoint.mul(n, .little) catch unreachable; |
| 181 | 181 | } |
| 182 | 182 |
lib/std/crypto/pcurves/secp256k1/scalar.zig+4-4| ... | ... | @@ -68,8 +68,8 @@ pub fn sub(a: CompressedScalar, b: CompressedScalar, endian: std.builtin.Endian) |
| 68 | 68 | } |
| 69 | 69 | |
| 70 | 70 | /// Return a random scalar |
| 71 | pub fn random(endian: std.builtin.Endian) CompressedScalar { | |
| 72 | return Scalar.random().toBytes(endian); | |
| 71 | pub fn random(io: std.Io, endian: std.builtin.Endian) CompressedScalar { | |
| 72 | return Scalar.random(io).toBytes(endian); | |
| 73 | 73 | } |
| 74 | 74 | |
| 75 | 75 | /// A scalar in unpacked representation. |
| ... | ... | @@ -170,10 +170,10 @@ pub const Scalar = struct { |
| 170 | 170 | } |
| 171 | 171 | |
| 172 | 172 | /// Return a random scalar < L. |
| 173 | pub fn random() Scalar { | |
| 173 | pub fn random(io: std.Io) Scalar { | |
| 174 | 174 | var s: [48]u8 = undefined; |
| 175 | 175 | while (true) { |
| 176 | crypto.random.bytes(&s); | |
| 176 | io.random(&s); | |
| 177 | 177 | const n = Scalar.fromBytes48(s, .little); |
| 178 | 178 | if (!n.isZero()) { |
| 179 | 179 | return n; |
lib/std/crypto/pcurves/tests/p256.zig+11-6| ... | ... | @@ -5,8 +5,9 @@ const testing = std.testing; |
| 5 | 5 | const P256 = @import("../p256.zig").P256; |
| 6 | 6 | |
| 7 | 7 | test "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); | |
| 10 | 11 | const dhA = try P256.basePoint.mul(dha, .little); |
| 11 | 12 | const dhB = try P256.basePoint.mul(dhb, .little); |
| 12 | 13 | const shareda = try dhA.mul(dhb, .little); |
| ... | ... | @@ -66,28 +67,32 @@ test "p256 test vectors - doubling" { |
| 66 | 67 | } |
| 67 | 68 | |
| 68 | 69 | test "p256 compressed sec1 encoding/decoding" { |
| 69 | const p = P256.random(); | |
| 70 | const io = testing.io; | |
| 71 | const p = P256.random(io); | |
| 70 | 72 | const s = p.toCompressedSec1(); |
| 71 | 73 | const q = try P256.fromSec1(&s); |
| 72 | 74 | try testing.expect(p.equivalent(q)); |
| 73 | 75 | } |
| 74 | 76 | |
| 75 | 77 | test "p256 uncompressed sec1 encoding/decoding" { |
| 76 | const p = P256.random(); | |
| 78 | const io = testing.io; | |
| 79 | const p = P256.random(io); | |
| 77 | 80 | const s = p.toUncompressedSec1(); |
| 78 | 81 | const q = try P256.fromSec1(&s); |
| 79 | 82 | try testing.expect(p.equivalent(q)); |
| 80 | 83 | } |
| 81 | 84 | |
| 82 | 85 | test "p256 public key is the neutral element" { |
| 86 | const io = testing.io; | |
| 83 | 87 | const n = P256.scalar.Scalar.zero.toBytes(.little); |
| 84 | const p = P256.random(); | |
| 88 | const p = P256.random(io); | |
| 85 | 89 | try testing.expectError(error.IdentityElement, p.mul(n, .little)); |
| 86 | 90 | } |
| 87 | 91 | |
| 88 | 92 | test "p256 public key is the neutral element (public verification)" { |
| 93 | const io = testing.io; | |
| 89 | 94 | const n = P256.scalar.Scalar.zero.toBytes(.little); |
| 90 | const p = P256.random(); | |
| 95 | const p = P256.random(io); | |
| 91 | 96 | try testing.expectError(error.IdentityElement, p.mulPublic(n, .little)); |
| 92 | 97 | } |
| 93 | 98 |
lib/std/crypto/pcurves/tests/p384.zig+11-6| ... | ... | @@ -5,8 +5,9 @@ const testing = std.testing; |
| 5 | 5 | const P384 = @import("../p384.zig").P384; |
| 6 | 6 | |
| 7 | 7 | test "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); | |
| 10 | 11 | const dhA = try P384.basePoint.mul(dha, .little); |
| 11 | 12 | const dhB = try P384.basePoint.mul(dhb, .little); |
| 12 | 13 | const shareda = try dhA.mul(dhb, .little); |
| ... | ... | @@ -67,7 +68,8 @@ test "p384 test vectors - doubling" { |
| 67 | 68 | } |
| 68 | 69 | |
| 69 | 70 | test "p384 compressed sec1 encoding/decoding" { |
| 70 | const p = P384.random(); | |
| 71 | const io = testing.io; | |
| 72 | const p = P384.random(io); | |
| 71 | 73 | const s0 = p.toUncompressedSec1(); |
| 72 | 74 | const s = p.toCompressedSec1(); |
| 73 | 75 | try testing.expectEqualSlices(u8, s0[1..49], s[1..49]); |
| ... | ... | @@ -76,21 +78,24 @@ test "p384 compressed sec1 encoding/decoding" { |
| 76 | 78 | } |
| 77 | 79 | |
| 78 | 80 | test "p384 uncompressed sec1 encoding/decoding" { |
| 79 | const p = P384.random(); | |
| 81 | const io = testing.io; | |
| 82 | const p = P384.random(io); | |
| 80 | 83 | const s = p.toUncompressedSec1(); |
| 81 | 84 | const q = try P384.fromSec1(&s); |
| 82 | 85 | try testing.expect(p.equivalent(q)); |
| 83 | 86 | } |
| 84 | 87 | |
| 85 | 88 | test "p384 public key is the neutral element" { |
| 89 | const io = testing.io; | |
| 86 | 90 | const n = P384.scalar.Scalar.zero.toBytes(.little); |
| 87 | const p = P384.random(); | |
| 91 | const p = P384.random(io); | |
| 88 | 92 | try testing.expectError(error.IdentityElement, p.mul(n, .little)); |
| 89 | 93 | } |
| 90 | 94 | |
| 91 | 95 | test "p384 public key is the neutral element (public verification)" { |
| 96 | const io = testing.io; | |
| 92 | 97 | const n = P384.scalar.Scalar.zero.toBytes(.little); |
| 93 | const p = P384.random(); | |
| 98 | const p = P384.random(io); | |
| 94 | 99 | try testing.expectError(error.IdentityElement, p.mulPublic(n, .little)); |
| 95 | 100 | } |
| 96 | 101 |
lib/std/crypto/pcurves/tests/secp256k1.zig+14-8| ... | ... | @@ -5,8 +5,9 @@ const testing = std.testing; |
| 5 | 5 | const Secp256k1 = @import("../secp256k1.zig").Secp256k1; |
| 6 | 6 | |
| 7 | 7 | test "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); | |
| 10 | 11 | const dhA = try Secp256k1.basePoint.mul(dha, .little); |
| 11 | 12 | const dhB = try Secp256k1.basePoint.mul(dhb, .little); |
| 12 | 13 | const shareda = try dhA.mul(dhb, .little); |
| ... | ... | @@ -15,8 +16,9 @@ test "secp256k1 ECDH key exchange" { |
| 15 | 16 | } |
| 16 | 17 | |
| 17 | 18 | test "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); | |
| 20 | 22 | const dhA = try Secp256k1.basePoint.mul(dha, .little); |
| 21 | 23 | const dhB = try Secp256k1.basePoint.mulPublic(dhb, .little); |
| 22 | 24 | const shareda = try dhA.mul(dhb, .little); |
| ... | ... | @@ -77,28 +79,32 @@ test "secp256k1 test vectors - doubling" { |
| 77 | 79 | } |
| 78 | 80 | |
| 79 | 81 | test "secp256k1 compressed sec1 encoding/decoding" { |
| 80 | const p = Secp256k1.random(); | |
| 82 | const io = testing.io; | |
| 83 | const p = Secp256k1.random(io); | |
| 81 | 84 | const s = p.toCompressedSec1(); |
| 82 | 85 | const q = try Secp256k1.fromSec1(&s); |
| 83 | 86 | try testing.expect(p.equivalent(q)); |
| 84 | 87 | } |
| 85 | 88 | |
| 86 | 89 | test "secp256k1 uncompressed sec1 encoding/decoding" { |
| 87 | const p = Secp256k1.random(); | |
| 90 | const io = testing.io; | |
| 91 | const p = Secp256k1.random(io); | |
| 88 | 92 | const s = p.toUncompressedSec1(); |
| 89 | 93 | const q = try Secp256k1.fromSec1(&s); |
| 90 | 94 | try testing.expect(p.equivalent(q)); |
| 91 | 95 | } |
| 92 | 96 | |
| 93 | 97 | test "secp256k1 public key is the neutral element" { |
| 98 | const io = testing.io; | |
| 94 | 99 | const n = Secp256k1.scalar.Scalar.zero.toBytes(.little); |
| 95 | const p = Secp256k1.random(); | |
| 100 | const p = Secp256k1.random(io); | |
| 96 | 101 | try testing.expectError(error.IdentityElement, p.mul(n, .little)); |
| 97 | 102 | } |
| 98 | 103 | |
| 99 | 104 | test "secp256k1 public key is the neutral element (public verification)" { |
| 105 | const io = testing.io; | |
| 100 | 106 | const n = Secp256k1.scalar.Scalar.zero.toBytes(.little); |
| 101 | const p = Secp256k1.random(); | |
| 107 | const p = Secp256k1.random(io); | |
| 102 | 108 | try testing.expectError(error.IdentityElement, p.mulPublic(n, .little)); |
| 103 | 109 | } |
| 104 | 110 |
lib/std/crypto/salsa20.zig+19-15| ... | ... | @@ -533,9 +533,9 @@ pub const SealedBox = struct { |
| 533 | 533 | |
| 534 | 534 | /// Encrypt a message `m` for a recipient whose public key is `public_key`. |
| 535 | 535 | /// `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 { | |
| 537 | 537 | debug.assert(c.len == m.len + seal_length); |
| 538 | var ekp = KeyPair.generate(); | |
| 538 | var ekp = KeyPair.generate(io); | |
| 539 | 539 | const nonce = createNonce(ekp.public_key, public_key); |
| 540 | 540 | c[0..public_length].* = ekp.public_key; |
| 541 | 541 | try Box.seal(c[Box.public_length..], m, nonce, public_key, ekp.secret_key); |
| ... | ... | @@ -573,29 +573,31 @@ test "(x)salsa20" { |
| 573 | 573 | } |
| 574 | 574 | |
| 575 | 575 | test "xsalsa20poly1305" { |
| 576 | const io = std.testing.io; | |
| 576 | 577 | var msg: [100]u8 = undefined; |
| 577 | 578 | var msg2: [msg.len]u8 = undefined; |
| 578 | 579 | var c: [msg.len]u8 = undefined; |
| 579 | 580 | var key: [XSalsa20Poly1305.key_length]u8 = undefined; |
| 580 | 581 | var nonce: [XSalsa20Poly1305.nonce_length]u8 = undefined; |
| 581 | 582 | 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); | |
| 585 | 586 | |
| 586 | 587 | XSalsa20Poly1305.encrypt(c[0..], &tag, msg[0..], "ad", nonce, key); |
| 587 | 588 | try XSalsa20Poly1305.decrypt(msg2[0..], c[0..], tag, "ad", nonce, key); |
| 588 | 589 | } |
| 589 | 590 | |
| 590 | 591 | test "xsalsa20poly1305 secretbox" { |
| 592 | const io = std.testing.io; | |
| 591 | 593 | var msg: [100]u8 = undefined; |
| 592 | 594 | var msg2: [msg.len]u8 = undefined; |
| 593 | 595 | var key: [XSalsa20Poly1305.key_length]u8 = undefined; |
| 594 | 596 | var nonce: [Box.nonce_length]u8 = undefined; |
| 595 | 597 | 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); | |
| 599 | 601 | |
| 600 | 602 | SecretBox.seal(boxed[0..], msg[0..], nonce, key); |
| 601 | 603 | try SecretBox.open(msg2[0..], boxed[0..], nonce, key); |
| ... | ... | @@ -604,15 +606,16 @@ test "xsalsa20poly1305 secretbox" { |
| 604 | 606 | test "xsalsa20poly1305 box" { |
| 605 | 607 | if (builtin.cpu.has(.riscv, .v) and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/24299 |
| 606 | 608 | |
| 609 | const io = std.testing.io; | |
| 607 | 610 | var msg: [100]u8 = undefined; |
| 608 | 611 | var msg2: [msg.len]u8 = undefined; |
| 609 | 612 | var nonce: [Box.nonce_length]u8 = undefined; |
| 610 | 613 | 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); | |
| 613 | 616 | |
| 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); | |
| 616 | 619 | try Box.seal(boxed[0..], msg[0..], nonce, kp1.public_key, kp2.secret_key); |
| 617 | 620 | try Box.open(msg2[0..], boxed[0..], nonce, kp2.public_key, kp1.secret_key); |
| 618 | 621 | } |
| ... | ... | @@ -620,13 +623,14 @@ test "xsalsa20poly1305 box" { |
| 620 | 623 | test "xsalsa20poly1305 sealedbox" { |
| 621 | 624 | if (builtin.cpu.has(.riscv, .v) and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/24299 |
| 622 | 625 | |
| 626 | const io = std.testing.io; | |
| 623 | 627 | var msg: [100]u8 = undefined; |
| 624 | 628 | var msg2: [msg.len]u8 = undefined; |
| 625 | 629 | var boxed: [msg.len + SealedBox.seal_length]u8 = undefined; |
| 626 | crypto.random.bytes(&msg); | |
| 630 | io.random(&msg); | |
| 627 | 631 | |
| 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); | |
| 630 | 634 | try SealedBox.open(msg2[0..], boxed[0..], kp); |
| 631 | 635 | } |
| 632 | 636 |
lib/std/crypto/scrypt.zig+5-6| ... | ... | @@ -20,7 +20,7 @@ const Error = pwhash.Error; |
| 20 | 20 | |
| 21 | 21 | const max_size = math.maxInt(usize); |
| 22 | 22 | const max_int = max_size >> 1; |
| 23 | const default_salt_len = 32; | |
| 23 | pub const default_salt_len = 32; | |
| 24 | 24 | const default_hash_len = 32; |
| 25 | 25 | const max_salt_len = 64; |
| 26 | 26 | const max_hash_len = 64; |
| ... | ... | @@ -417,10 +417,9 @@ const PhcFormatHasher = struct { |
| 417 | 417 | password: []const u8, |
| 418 | 418 | params: Params, |
| 419 | 419 | buf: []u8, |
| 420 | /// Filled with cryptographically secure entropy. | |
| 421 | salt: []const u8, | |
| 420 | 422 | ) HasherError![]const u8 { |
| 421 | var salt: [default_salt_len]u8 = undefined; | |
| 422 | crypto.random.bytes(&salt); | |
| 423 | ||
| 424 | 423 | var hash: [default_hash_len]u8 = undefined; |
| 425 | 424 | try kdf(allocator, &hash, password, &salt, params); |
| 426 | 425 | |
| ... | ... | @@ -466,9 +465,9 @@ const CryptFormatHasher = struct { |
| 466 | 465 | password: []const u8, |
| 467 | 466 | params: Params, |
| 468 | 467 | buf: []u8, |
| 468 | /// Filled with cryptographically secure entropy. | |
| 469 | salt_bin: []const u8, | |
| 469 | 470 | ) HasherError![]const u8 { |
| 470 | var salt_bin: [default_salt_len]u8 = undefined; | |
| 471 | crypto.random.bytes(&salt_bin); | |
| 472 | 471 | const salt = crypt_format.saltFromBin(salt_bin.len, salt_bin); |
| 473 | 472 | |
| 474 | 473 | 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 { |
| 180 | 180 | } |
| 181 | 181 | |
| 182 | 182 | test eql { |
| 183 | const random = std.crypto.random; | |
| 183 | const io = std.testing.io; | |
| 184 | 184 | const expect = std.testing.expect; |
| 185 | 185 | var a: [100]u8 = undefined; |
| 186 | 186 | var b: [100]u8 = undefined; |
| 187 | random.bytes(a[0..]); | |
| 188 | random.bytes(b[0..]); | |
| 187 | io.random(&a); | |
| 188 | io.random(&b); | |
| 189 | 189 | try expect(!eql([100]u8, a, b)); |
| 190 | 190 | a = b; |
| 191 | 191 | try expect(eql([100]u8, a, b)); |
| 192 | 192 | } |
| 193 | 193 | |
| 194 | 194 | test "eql (vectors)" { |
| 195 | const random = std.crypto.random; | |
| 195 | const io = std.testing.io; | |
| 196 | 196 | const expect = std.testing.expect; |
| 197 | 197 | var a: [100]u8 = undefined; |
| 198 | 198 | var b: [100]u8 = undefined; |
| 199 | random.bytes(a[0..]); | |
| 200 | random.bytes(b[0..]); | |
| 199 | io.random(&a); | |
| 200 | io.random(&b); | |
| 201 | 201 | const v1: @Vector(100, u8) = a; |
| 202 | 202 | const v2: @Vector(100, u8) = b; |
| 203 | 203 | try expect(!eql(@Vector(100, u8), v1, v2)); |
| ... | ... | @@ -220,9 +220,10 @@ test compare { |
| 220 | 220 | } |
| 221 | 221 | |
| 222 | 222 | test "add and sub" { |
| 223 | const io = std.testing.io; | |
| 224 | ||
| 223 | 225 | const expectEqual = std.testing.expectEqual; |
| 224 | 226 | const expectEqualSlices = std.testing.expectEqualSlices; |
| 225 | const random = std.crypto.random; | |
| 226 | 227 | const len = 32; |
| 227 | 228 | var a: [len]u8 = undefined; |
| 228 | 229 | var b: [len]u8 = undefined; |
| ... | ... | @@ -230,8 +231,8 @@ test "add and sub" { |
| 230 | 231 | const zero = [_]u8{0} ** len; |
| 231 | 232 | var iterations: usize = 100; |
| 232 | 233 | while (iterations != 0) : (iterations -= 1) { |
| 233 | random.bytes(&a); | |
| 234 | random.bytes(&b); | |
| 234 | io.random(&a); | |
| 235 | io.random(&b); | |
| 235 | 236 | const endian = if (iterations % 2 == 0) Endian.big else Endian.little; |
| 236 | 237 | _ = sub(u8, &a, &b, &c, endian); // a-b |
| 237 | 238 | _ = add(u8, &c, &b, &c, endian); // (a-b)+b |
| ... | ... | @@ -243,11 +244,11 @@ test "add and sub" { |
| 243 | 244 | } |
| 244 | 245 | |
| 245 | 246 | test classify { |
| 246 | const random = std.crypto.random; | |
| 247 | const io = std.testing.io; | |
| 247 | 248 | const expect = std.testing.expect; |
| 248 | 249 | |
| 249 | 250 | var secret: [32]u8 = undefined; |
| 250 | random.bytes(&secret); | |
| 251 | io.random(&secret); | |
| 251 | 252 | |
| 252 | 253 | // Input of the hash function is marked as secret |
| 253 | 254 | classify(&secret); |
lib/std/crypto/tls/Client.zig+7-7| ... | ... | @@ -109,7 +109,7 @@ pub const Options = struct { |
| 109 | 109 | read_buffer: []u8, |
| 110 | 110 | /// Cryptographically secure random bytes. The pointer is not captured; data is only |
| 111 | 111 | /// read during `init`. |
| 112 | entropy: *const [176]u8, | |
| 112 | entropy: *const [240]u8, | |
| 113 | 113 | /// Current time according to the wall clock / calendar, in seconds. |
| 114 | 114 | realtime_now_seconds: i64, |
| 115 | 115 | |
| ... | ... | @@ -200,7 +200,7 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client |
| 200 | 200 | var server_hello_rand: [32]u8 = undefined; |
| 201 | 201 | const legacy_session_id = options.entropy[32..64].*; |
| 202 | 202 | |
| 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) { | |
| 204 | 204 | // Only possible to happen if the seed is all zeroes. |
| 205 | 205 | error.IdentityElement => return error.InsufficientEntropy, |
| 206 | 206 | }; |
| ... | ... | @@ -1330,12 +1330,12 @@ const KeyShare = struct { |
| 1330 | 1330 | crypto.dh.X25519.shared_length, |
| 1331 | 1331 | ); |
| 1332 | 1332 | |
| 1333 | fn init(seed: [112]u8) error{IdentityElement}!KeyShare { | |
| 1333 | fn init(seed: *const [176]u8) error{IdentityElement}!KeyShare { | |
| 1334 | 1334 | 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].*), | |
| 1339 | 1339 | .sk_buf = undefined, |
| 1340 | 1340 | .sk_len = 0, |
| 1341 | 1341 | }; |
lib/std/fs/test.zig+1-1| ... | ... | @@ -1761,7 +1761,7 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" { |
| 1761 | 1761 | const io = testing.io; |
| 1762 | 1762 | |
| 1763 | 1763 | var random_bytes: [12]u8 = undefined; |
| 1764 | std.crypto.random.bytes(&random_bytes); | |
| 1764 | io.random(&random_bytes); | |
| 1765 | 1765 | |
| 1766 | 1766 | var random_b64: [std.fs.base64_encoder.calcSize(random_bytes.len)]u8 = undefined; |
| 1767 | 1767 | _ = std.fs.base64_encoder.encode(&random_b64, &random_bytes); |
lib/std/http/Client.zig+2-2| ... | ... | @@ -321,8 +321,8 @@ pub const Connection = struct { |
| 321 | 321 | assert(base.ptr + alloc_len == socket_read_buffer.ptr + socket_read_buffer.len); |
| 322 | 322 | @memcpy(host_buffer, remote_host.bytes); |
| 323 | 323 | 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); | |
| 326 | 326 | tls.* = .{ |
| 327 | 327 | .connection = .{ |
| 328 | 328 | .client = client, |
lib/std/os/linux/tls.zig+5-7| ... | ... | @@ -531,13 +531,11 @@ pub fn prepareArea(area: []u8) usize { |
| 531 | 531 | }; |
| 532 | 532 | } |
| 533 | 533 | |
| 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. | |
| 540 | var 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. | |
| 538 | var main_thread_area_buffer: [0x1000]u8 align(page_size_min) = undefined; | |
| 541 | 539 | |
| 542 | 540 | /// Computes the layout of the static TLS area, allocates the area, initializes all of its fields, |
| 543 | 541 | /// and assigns the architecture-specific value to the TP register. |
lib/std/posix/test.zig-10| ... | ... | @@ -33,16 +33,6 @@ test "check WASI CWD" { |
| 33 | 33 | } |
| 34 | 34 | } |
| 35 | 35 | |
| 36 | test "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 | ||
| 46 | 36 | test "getuid" { |
| 47 | 37 | if (native_os == .windows or native_os == .wasi) return error.SkipZigTest; |
| 48 | 38 | _ = posix.getuid(); |
lib/std/testing.zig+1-1| ... | ... | @@ -631,7 +631,7 @@ pub const TmpDir = struct { |
| 631 | 631 | pub fn tmpDir(opts: Io.Dir.OpenOptions) TmpDir { |
| 632 | 632 | comptime assert(builtin.is_test); |
| 633 | 633 | var random_bytes: [TmpDir.random_bytes_count]u8 = undefined; |
| 634 | std.crypto.random.bytes(&random_bytes); | |
| 634 | io.random(&random_bytes); | |
| 635 | 635 | var sub_path: [TmpDir.sub_path_len]u8 = undefined; |
| 636 | 636 | _ = std.fs.base64_encoder.encode(&sub_path, &random_bytes); |
| 637 | 637 |
src/Compilation.zig+13-4| ... | ... | @@ -2942,7 +2942,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 2942 | 2942 | .none => |none| { |
| 2943 | 2943 | assert(none.tmp_artifact_directory == null); |
| 2944 | 2944 | none.tmp_artifact_directory = d: { |
| 2945 | tmp_dir_rand_int = std.crypto.random.int(u64); | |
| 2945 | io.random(@ptrCast(&tmp_dir_rand_int)); | |
| 2946 | 2946 | const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int); |
| 2947 | 2947 | const path = try comp.dirs.local_cache.join(arena, &.{tmp_dir_sub_path}); |
| 2948 | 2948 | 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 |
| 3023 | 3023 | |
| 3024 | 3024 | // Compile the artifacts to a temporary directory. |
| 3025 | 3025 | whole.tmp_artifact_directory = d: { |
| 3026 | tmp_dir_rand_int = std.crypto.random.int(u64); | |
| 3026 | io.random(@ptrCast(&tmp_dir_rand_int)); | |
| 3027 | 3027 | const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int); |
| 3028 | 3028 | const path = try comp.dirs.local_cache.join(arena, &.{tmp_dir_sub_path}); |
| 3029 | 3029 | const handle = comp.dirs.local_cache.handle.createDirPathOpen(io, tmp_dir_sub_path, .{}) catch |err| { |
| ... | ... | @@ -5759,7 +5759,11 @@ pub fn translateC( |
| 5759 | 5759 | |
| 5760 | 5760 | const gpa = comp.gpa; |
| 5761 | 5761 | 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 | }; | |
| 5763 | 5767 | const tmp_sub_path = "tmp" ++ fs.path.sep_str ++ tmp_basename; |
| 5764 | 5768 | const cache_dir = comp.dirs.local_cache.handle; |
| 5765 | 5769 | var cache_tmp_dir = try cache_dir.createDirPathOpen(io, tmp_sub_path, .{}); |
| ... | ... | @@ -6889,8 +6893,13 @@ fn spawnZigRc( |
| 6889 | 6893 | } |
| 6890 | 6894 | |
| 6891 | 6895 | pub 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 | }; | |
| 6892 | 6902 | const s = fs.path.sep_str; |
| 6893 | const rand_int = std.crypto.random.int(u64); | |
| 6894 | 6903 | if (comp.dirs.local_cache.path) |p| { |
| 6895 | 6904 | return std.fmt.allocPrint(ally, "{s}" ++ s ++ "tmp" ++ s ++ "{x}-{s}", .{ p, rand_int, suffix }); |
| 6896 | 6905 | } else { |
src/Package.zig+2-2| ... | ... | @@ -14,9 +14,9 @@ pub const Fingerprint = packed struct(u64) { |
| 14 | 14 | id: u32, |
| 15 | 15 | checksum: u32, |
| 16 | 16 | |
| 17 | pub fn generate(name: []const u8) Fingerprint { | |
| 17 | pub fn generate(rng: std.Random, name: []const u8) Fingerprint { | |
| 18 | 18 | return .{ |
| 19 | .id = std.crypto.random.intRangeLessThan(u32, 1, 0xffffffff), | |
| 19 | .id = rng.intRangeLessThan(u32, 1, 0xffffffff), | |
| 20 | 20 | .checksum = std.hash.Crc32.hash(name), |
| 21 | 21 | }; |
| 22 | 22 | } |
src/Package/Fetch.zig+13-3| ... | ... | @@ -494,7 +494,11 @@ fn runResource( |
| 494 | 494 | const eb = &f.error_bundle; |
| 495 | 495 | const s = fs.path.sep_str; |
| 496 | 496 | 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 | }; | |
| 498 | 502 | const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(rand_int); |
| 499 | 503 | |
| 500 | 504 | const package_sub_path = blk: { |
| ... | ... | @@ -690,7 +694,9 @@ fn loadManifest(f: *Fetch, pkg_root: Cache.Path) RunError!void { |
| 690 | 694 | return error.FetchFailed; |
| 691 | 695 | } |
| 692 | 696 | |
| 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(), .{ | |
| 694 | 700 | .allow_missing_paths_field = f.allow_missing_paths_field, |
| 695 | 701 | .allow_missing_fingerprint = f.allow_missing_fingerprint, |
| 696 | 702 | .allow_name_string = f.allow_name_string, |
| ... | ... | @@ -1305,7 +1311,11 @@ fn unzip( |
| 1305 | 1311 | zip_path[prefix.len + random_len ..].* = suffix.*; |
| 1306 | 1312 | |
| 1307 | 1313 | 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 | }; | |
| 1309 | 1319 | zip_path[prefix.len..][0..random_len].* = std.fmt.hex(random_integer); |
| 1310 | 1320 | |
| 1311 | 1321 | break cache_root.handle.createFile(io, &zip_path, .{ |
src/Package/Manifest.zig+5-5| ... | ... | @@ -57,7 +57,7 @@ pub const ParseOptions = struct { |
| 57 | 57 | |
| 58 | 58 | pub const Error = Allocator.Error; |
| 59 | 59 | |
| 60 | pub fn parse(gpa: Allocator, ast: Ast, options: ParseOptions) Error!Manifest { | |
| 60 | pub fn parse(gpa: Allocator, ast: Ast, rng: std.Random, options: ParseOptions) Error!Manifest { | |
| 61 | 61 | const main_node_index = ast.nodeData(.root).node; |
| 62 | 62 | |
| 63 | 63 | var arena_instance = std.heap.ArenaAllocator.init(gpa); |
| ... | ... | @@ -87,7 +87,7 @@ pub fn parse(gpa: Allocator, ast: Ast, options: ParseOptions) Error!Manifest { |
| 87 | 87 | defer p.dependencies.deinit(gpa); |
| 88 | 88 | defer p.paths.deinit(gpa); |
| 89 | 89 | |
| 90 | p.parseRoot(main_node_index) catch |err| switch (err) { | |
| 90 | p.parseRoot(main_node_index, rng) catch |err| switch (err) { | |
| 91 | 91 | error.ParseFailure => assert(p.errors.items.len > 0), |
| 92 | 92 | else => |e| return e, |
| 93 | 93 | }; |
| ... | ... | @@ -157,7 +157,7 @@ const Parse = struct { |
| 157 | 157 | |
| 158 | 158 | const InnerError = error{ ParseFailure, OutOfMemory }; |
| 159 | 159 | |
| 160 | fn parseRoot(p: *Parse, node: Ast.Node.Index) !void { | |
| 160 | fn parseRoot(p: *Parse, node: Ast.Node.Index, rng: std.Random) !void { | |
| 161 | 161 | const ast = p.ast; |
| 162 | 162 | const main_token = ast.nodeMainToken(node); |
| 163 | 163 | |
| ... | ... | @@ -217,13 +217,13 @@ const Parse = struct { |
| 217 | 217 | if (fingerprint) |n| { |
| 218 | 218 | if (!n.validate(p.name)) { |
| 219 | 219 | 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(), | |
| 221 | 221 | }); |
| 222 | 222 | } |
| 223 | 223 | p.id = n.id; |
| 224 | 224 | } else if (!p.allow_missing_fingerprint) { |
| 225 | 225 | 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(), | |
| 227 | 227 | }); |
| 228 | 228 | } else { |
| 229 | 229 | p.id = 0; |
src/link.zig+6-1| ... | ... | @@ -616,8 +616,13 @@ pub const File = struct { |
| 616 | 616 | // it will return ETXTBSY. So instead, we copy the file, atomically rename it |
| 617 | 617 | // over top of the exe path, and then proceed normally. This changes the inode, |
| 618 | 618 | // avoiding the error. |
| 619 | const random_integer = r: { | |
| 620 | var x: u32 = undefined; | |
| 621 | io.random(@ptrCast(&x)); | |
| 622 | break :r x; | |
| 623 | }; | |
| 619 | 624 | 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, | |
| 621 | 626 | }); |
| 622 | 627 | defer gpa.free(tmp_sub_path); |
| 623 | 628 | 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 |
| 1636 | 1636 | const err = switch (first_err) { |
| 1637 | 1637 | error.NameTooLong => err: { |
| 1638 | 1638 | 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 | }; | |
| 1640 | 1644 | const rsp_path = "tmp" ++ s ++ std.fmt.hex(rand_int) ++ ".rsp"; |
| 1641 | 1645 | |
| 1642 | 1646 | const rsp_file = try comp.dirs.local_cache.handle.createFile(io, rsp_path, .{}); |
src/main.zig+19-12| ... | ... | @@ -3395,7 +3395,7 @@ fn buildOutputType( |
| 3395 | 3395 | // "-" is stdin. Dump it to a real file. |
| 3396 | 3396 | const sep = fs.path.sep_str; |
| 3397 | 3397 | 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), | |
| 3399 | 3399 | }); |
| 3400 | 3400 | try dirs.local_cache.handle.createDirPath(io, "tmp"); |
| 3401 | 3401 | |
| ... | ... | @@ -4433,7 +4433,7 @@ fn runOrTest( |
| 4433 | 4433 | try argv.append(exe_path); |
| 4434 | 4434 | if (arg_mode == .zig_test) { |
| 4435 | 4435 | 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)}), | |
| 4437 | 4437 | ); |
| 4438 | 4438 | } |
| 4439 | 4439 | } else { |
| ... | ... | @@ -4763,7 +4763,8 @@ fn cmdInit(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) ! |
| 4763 | 4763 | const cwd_basename = fs.path.basename(cwd_path); |
| 4764 | 4764 | const sanitized_root_name = try sanitizeExampleName(arena, cwd_basename); |
| 4765 | 4765 | |
| 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); | |
| 4767 | 4768 | |
| 4768 | 4769 | switch (template) { |
| 4769 | 4770 | .example => { |
| ... | ... | @@ -4919,7 +4920,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, |
| 4919 | 4920 | |
| 4920 | 4921 | try child_argv.appendSlice(&.{ |
| 4921 | 4922 | "--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)}), | |
| 4923 | 4924 | }); |
| 4924 | 4925 | const argv_index_seed = child_argv.items.len - 1; |
| 4925 | 4926 | |
| ... | ... | @@ -4937,7 +4938,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, |
| 4937 | 4938 | // the strategy is to choose a temporary file name ahead of time, and then |
| 4938 | 4939 | // read this file in the parent to obtain the results, in the case the child |
| 4939 | 4940 | // 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)); | |
| 4941 | 4942 | try child_argv.append("-Z" ++ results_tmp_file_nonce); |
| 4942 | 4943 | |
| 4943 | 4944 | var color: Color = .auto; |
| ... | ... | @@ -7223,7 +7224,7 @@ fn createDependenciesModule( |
| 7223 | 7224 | ) !*Package.Module { |
| 7224 | 7225 | // Atomically create the file in a directory named after the hash of its contents. |
| 7225 | 7226 | const basename = "dependencies.zig"; |
| 7226 | const rand_int = std.crypto.random.int(u64); | |
| 7227 | const rand_int = randInt(io, u64); | |
| 7227 | 7228 | const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int); |
| 7228 | 7229 | { |
| 7229 | 7230 | var tmp_dir = try dirs.local_cache.handle.createDirPathOpen(io, tmp_dir_sub_path, .{}); |
| ... | ... | @@ -7339,6 +7340,8 @@ fn loadManifest( |
| 7339 | 7340 | io: Io, |
| 7340 | 7341 | options: LoadManifestOptions, |
| 7341 | 7342 | ) !struct { Package.Manifest, Ast } { |
| 7343 | const rng: std.Random.IoSource = .{ .io = io }; | |
| 7344 | ||
| 7342 | 7345 | const manifest_bytes = while (true) { |
| 7343 | 7346 | break options.dir.readFileAllocOptions( |
| 7344 | 7347 | io, |
| ... | ... | @@ -7360,15 +7363,13 @@ fn loadManifest( |
| 7360 | 7363 | , .{ |
| 7361 | 7364 | options.root_name, |
| 7362 | 7365 | build_options.version, |
| 7363 | Package.Fingerprint.generate(options.root_name).int(), | |
| 7366 | Package.Fingerprint.generate(rng.interface(), options.root_name).int(), | |
| 7364 | 7367 | }) 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 }); | |
| 7366 | 7369 | }; |
| 7367 | 7370 | continue; |
| 7368 | 7371 | }, |
| 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 }), | |
| 7372 | 7373 | }; |
| 7373 | 7374 | }; |
| 7374 | 7375 | var ast = try Ast.parse(gpa, manifest_bytes, .zon); |
| ... | ... | @@ -7379,7 +7380,7 @@ fn loadManifest( |
| 7379 | 7380 | process.exit(2); |
| 7380 | 7381 | } |
| 7381 | 7382 | |
| 7382 | var manifest = try Package.Manifest.parse(gpa, ast, .{}); | |
| 7383 | var manifest = try Package.Manifest.parse(gpa, ast, rng.interface(), .{}); | |
| 7383 | 7384 | errdefer manifest.deinit(gpa); |
| 7384 | 7385 | |
| 7385 | 7386 | if (manifest.errors.len > 0) { |
| ... | ... | @@ -7632,3 +7633,9 @@ fn setThreadLimit(n: usize) void { |
| 7632 | 7633 | threaded_impl_ptr.setAsyncLimit(limit); |
| 7633 | 7634 | threaded_impl_ptr.concurrent_limit = limit; |
| 7634 | 7635 | } |
| 7636 | ||
| 7637 | fn 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 { |
| 10 | 10 | |
| 11 | 11 | try out.writeAll("Welcome to the Guess Number Game in Zig.\n"); |
| 12 | 12 | |
| 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; | |
| 14 | 15 | |
| 15 | 16 | while (true) { |
| 16 | 17 | 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 { |
| 78 | 78 | const code = try parseManifest(arena, source_bytes); |
| 79 | 79 | const source = stripManifest(source_bytes); |
| 80 | 80 | |
| 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 }); | |
| 84 | 85 | Dir.cwd().createDirPath(io, tmp_dir_path) catch |err| |
| 85 | 86 | fatal("unable to create tmp dir '{s}': {t}", .{ tmp_dir_path, err }); |
| 86 | 87 | 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 { |
| 100 | 100 | const prog_node = std.Progress.start(io, .{}); |
| 101 | 101 | defer prog_node.end(); |
| 102 | 102 | |
| 103 | const rand_int = std.crypto.random.int(u64); | |
| 103 | const rand_int = rand64(io); | |
| 104 | 104 | const tmp_dir_path = "tmp_" ++ std.fmt.hex(rand_int); |
| 105 | 105 | var tmp_dir = try Dir.cwd().createDirPathOpen(io, tmp_dir_path, .{}); |
| 106 | 106 | defer { |
| ... | ... | @@ -452,20 +452,19 @@ const Eval = struct { |
| 452 | 452 | std.debug.assert(eval.target.backend == .sema); |
| 453 | 453 | return; |
| 454 | 454 | }; |
| 455 | const io = eval.io; | |
| 455 | 456 | |
| 456 | 457 | const binary_path = switch (eval.target.backend) { |
| 457 | 458 | .sema => unreachable, |
| 458 | 459 | .selfhosted, .llvm => emitted_path, |
| 459 | 460 | .cbe => bin: { |
| 460 | const rand_int = std.crypto.random.int(u64); | |
| 461 | const rand_int = rand64(io); | |
| 461 | 462 | const out_bin_name = "./out_" ++ std.fmt.hex(rand_int); |
| 462 | 463 | try eval.buildCOutput(emitted_path, out_bin_name, prog_node); |
| 463 | 464 | break :bin out_bin_name; |
| 464 | 465 | }, |
| 465 | 466 | }; |
| 466 | 467 | |
| 467 | const io = eval.io; | |
| 468 | ||
| 469 | 468 | var argv_buf: [2][]const u8 = undefined; |
| 470 | 469 | const argv: []const []const u8, const is_foreign: bool = sw: switch (std.zig.system.getExternalExecutor( |
| 471 | 470 | io, |
| ... | ... | @@ -957,3 +956,9 @@ fn parseExpectedError(str: []const u8, l: usize) Case.ExpectedError { |
| 957 | 956 | .msg = message, |
| 958 | 957 | }; |
| 959 | 958 | } |
| 959 | ||
| 960 | fn rand64(io: Io) u64 { | |
| 961 | var x: u64 = undefined; | |
| 962 | io.random(@ptrCast(&x)); | |
| 963 | return x; | |
| 964 | } |