-
Notifications
You must be signed in to change notification settings - Fork 454
/
Copy pathRandom.swift
executable file
·71 lines (63 loc) · 2.37 KB
/
Random.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//
// Random.swift
// BigInt
//
// Created by Károly Lőrentey on 2016-01-04.
// Copyright © 2016-2017 Károly Lőrentey.
//
import Foundation
#if os(Linux) || os(FreeBSD)
import Glibc
#endif
extension BigUInt {
//MARK: Random Integers
/// Create a big integer consisting of `width` uniformly distributed random bits.
///
/// - Returns: A big integer less than `1 << width`.
/// - Note: This function uses `arc4random_buf` to generate random bits.
public static func randomInteger(withMaximumWidth width: Int) -> BigUInt {
guard width > 0 else { return 0 }
let byteCount = (width + 7) / 8
assert(byteCount > 0)
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: byteCount)
#if os(Linux) || os(FreeBSD)
let fd = open("/dev/urandom", O_RDONLY)
defer {
close(fd)
}
let _ = read(fd, buffer, MemoryLayout<UInt8>.size * byteCount)
#else
arc4random_buf(buffer, byteCount)
#endif
if width % 8 != 0 {
buffer[0] &= UInt8(1 << (width % 8) - 1)
}
defer {
buffer.deinitialize(count: byteCount)
buffer.deallocate()
}
return BigUInt(Data(bytesNoCopy: buffer, count: byteCount, deallocator: .none))
}
/// Create a big integer consisting of `width-1` uniformly distributed random bits followed by a one bit.
///
/// - Returns: A random big integer whose width is `width`.
/// - Note: This function uses `arc4random_buf` to generate random bits.
public static func randomInteger(withExactWidth width: Int) -> BigUInt {
guard width > 1 else { return BigUInt(width) }
var result = randomInteger(withMaximumWidth: width - 1)
result[(width - 1) / Word.bitWidth] |= 1 << Word((width - 1) % Word.bitWidth)
return result
}
/// Create a uniformly distributed random integer that's less than the specified limit.
///
/// - Returns: A random big integer that is less than `limit`.
/// - Note: This function uses `arc4random_buf` to generate random bits.
public static func randomInteger(lessThan limit: BigUInt) -> BigUInt {
let width = limit.bitWidth
var random = randomInteger(withMaximumWidth: width)
while random >= limit {
random = randomInteger(withMaximumWidth: width)
}
return random
}
}