Skip to content

[4.2][stdlib] Update default generator to SystemRandomNumberGenerator #17990

New issue

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

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

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions stdlib/public/core/Bool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,16 @@ public struct Bool {
/// print("Maybe another try?")
/// }
///
/// `Bool.random()` uses the default random generator, `Random.default`. The
/// call in the example above is equivalent to
/// `Bool.random(using: &Random.default)`.
/// `Bool.random()` uses the default random generator,
/// `SystemRandomNumberGenerator`. To supply a non-default generator, call the
/// equivalent method that takes one as an argument.
///
/// - Returns: Either `true` or `false`, randomly chosen with equal
/// probability.
@inlinable
public static func random() -> Bool {
return Bool.random(using: &Random.default)
var g = SystemRandomNumberGenerator()
return Bool.random(using: &g)
}
}

Expand Down
3 changes: 2 additions & 1 deletion stdlib/public/core/Collection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1061,7 +1061,8 @@ extension Collection {
/// empty, the method returns `nil`.
@inlinable
public func randomElement() -> Element? {
return randomElement(using: &Random.default)
var g = SystemRandomNumberGenerator()
return randomElement(using: &g)
}

/// Do not use this method directly; call advanced(by: n) instead.
Expand Down
6 changes: 4 additions & 2 deletions stdlib/public/core/CollectionAlgorithms.swift
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,8 @@ extension Sequence {
/// - Complexity: O(*n*)
@inlinable
public func shuffled() -> [Element] {
return shuffled(using: &Random.default)
var g = SystemRandomNumberGenerator()
return shuffled(using: &g)
}
}

Expand Down Expand Up @@ -471,7 +472,8 @@ extension MutableCollection where Self : RandomAccessCollection {
/// - Complexity: O(*n*)
@inlinable
public mutating func shuffle() {
shuffle(using: &Random.default)
var g = SystemRandomNumberGenerator()
shuffle(using: &g)
}
}

Expand Down
3 changes: 2 additions & 1 deletion stdlib/public/core/FloatingPoint.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -2515,7 +2515,8 @@ where Self.RawSignificand : FixedWidthInteger {
/// - Returns: A random value within the bounds of `range`.
@inlinable
public static func random(in range: ${Range}<Self>) -> Self {
return Self.random(in: range, using: &Random.default)
var g = SystemRandomNumberGenerator()
return Self.random(in: range, using: &g)
}
}

Expand Down
3 changes: 2 additions & 1 deletion stdlib/public/core/Integers.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -2629,7 +2629,8 @@ extension FixedWidthInteger {
/// - Returns: A random value within the bounds of `range`.
@inlinable
public static func random(in range: ${Range}<Self>) -> Self {
return Self.random(in: range, using: &Random.default)
var g = SystemRandomNumberGenerator()
return Self.random(in: range, using: &g)
}
}

Expand Down
38 changes: 19 additions & 19 deletions stdlib/public/core/Random.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import SwiftShims
/// }
///
/// static func random() -> Weekday {
/// return Weekday.randomWeekday(using: &Random.default)
/// return Weekday.random(using: &Random.default)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example should be updated to reflect the new name & usage.

/// }
/// }
///
Expand Down Expand Up @@ -60,6 +60,7 @@ public protocol RandomNumberGenerator {
}

extension RandomNumberGenerator {
@inlinable
public mutating func _fill(bytes buffer: UnsafeMutableRawBufferPointer) {
// FIXME: Optimize
var chunk: UInt64 = 0
Expand Down Expand Up @@ -112,46 +113,45 @@ extension RandomNumberGenerator {
/// The default source of random data.
///
/// When you generate random values, shuffle a collection, or perform another
/// operation that depends on random data, this type's `default` property is
/// the generator used by default. For example, the two method calls in this
/// example are equivalent:
/// operation that depends on random data, this type's `default` property is the
/// generator used by default. For example, the two method calls in this example
/// are equivalent:
///
/// let x = Int.random(in: 1...100)
/// let y = Int.random(in: 1...100, using: &Random.default)
/// var g = SystemRandomNumberGenerator()
/// let y = Int.random(in: 1...100, using: &g)
///
/// `Random.default` is automatically seeded, is safe to use in multiple
/// threads, and uses a cryptographically secure algorithm whenever possible.
/// `SystemRandomNumberGenerator` is automatically seeded, is safe to use in
/// multiple threads, and uses a cryptographically secure algorithm whenever
/// possible.
///
/// Platform Implementation of `Random`
/// ===================================
///
/// While the `Random.default` generator is automatically seeded and
/// thread-safe on every platform, the cryptographic quality of the stream of
/// random data produced by the generator may vary. For more detail, see the
/// While the `SystemRandomNumberGenerator` generator is automatically seeded
/// and thread-safe on every platform, the cryptographic quality of the stream
/// of random data produced by the generator may vary. For more detail, see the
/// documentation for the APIs used by each platform.
///
/// - Apple platforms use `arc4random_buf(3)`.
/// - Linux platforms use `getrandom(2)` when available; otherwise, they read
/// from `/dev/urandom`.
public struct Random : RandomNumberGenerator {
/// The default instance of the `Random` random number generator.
public static var `default`: Random {
get { return Random() }
set { /* Discard */ }
}

private init() {}
@_fixed_layout
public struct SystemRandomNumberGenerator : RandomNumberGenerator {
@inlinable
public init() { }

/// Returns a value from a uniform, independent distribution of binary data.
///
/// - Returns: An unsigned 64-bit random value.
@effects(releasenone)
@inlinable
public mutating func next() -> UInt64 {
var random: UInt64 = 0
_stdlib_random(&random, MemoryLayout<UInt64>.size)
return random
}

@inlinable
public mutating func _fill(bytes buffer: UnsafeMutableRawBufferPointer) {
if !buffer.isEmpty {
_stdlib_random(buffer.baseAddress!, buffer.count)
Expand Down
5 changes: 3 additions & 2 deletions validation-test/stdlib/Random.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ RandomTests.test("_fill(bytes:)") {
expectEqual(bytes1, zeros)
expectEqual(bytes2, zeros)

bytes1.withUnsafeMutableBytes { Random.default._fill(bytes: $0) }
var g = SystemRandomNumberGenerator()
bytes1.withUnsafeMutableBytes { g._fill(bytes: $0) }
expectNotEqual(bytes1, bytes2)
expectNotEqual(bytes1, zeros)

bytes2.withUnsafeMutableBytes { Random.default._fill(bytes: $0) }
bytes2.withUnsafeMutableBytes { g._fill(bytes: $0) }
expectNotEqual(bytes1, bytes2)
expectNotEqual(bytes2, zeros)
}
Expand Down