Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Generate Lottery Numbers using CryptoKit
// Written by Thomas Durand (c)2019 ; all right reserved
// See https://www.thomasdurand.fr/swift/cryptokit/2019/06/25/generating-lottery-numbers-with-cryptokit.html for more context
/// Represent one `k among n` operation
struct Draw {
/// The number of number to draw (ie k)
let draw: UInt
/// The range of numbers to draw within (ie n)
let among: ClosedRange<Int>
/// Generate `draw` numbers within `among`
func random() -> Set<Int> {
var drawable = Set(among), drawnNumbers = Set<Int>()
var generator = CryptoKitRandomNumberGenerator()
while drawnNumbers.count < draw {
guard let drawn = drawable.randomElement(using: &generator) else {
break
}
drawable.remove(drawn)
drawnNumbers.insert(drawn)
}
return drawnNumbers
}
}
struct Lottery {
/// The draws for that lottery
/// Example draw 5 numbers within 1 and 49 & 1 number within 1 and 10.
let draws: [Draw]
/// Generate a lottery draw randomly
func random() -> [Set<Int>] {
return draws.map { $0.random() }
}
}
extension Lottery {
static let frenchLoto = Lottery(draws: [
Draw(draw: 5, among: 1...49),
Draw(draw: 1, among: 1...10)
])
static let euromillion = Lottery(draws: [
Draw(draw: 5, among: 1...50),
Draw(draw: 2, among: 1...12)
])
}
import CryptoKit
/// RandomNumberGenerator using CryptoKit
struct CryptoKitRandomNumberGenerator: RandomNumberGenerator {
mutating func next<T>() -> T where T : FixedWidthInteger, T : UnsignedInteger {
// Let generate a symmetric key using CryptoKit. It'll be generated using best cryptographic practices to have strong randomness.
// T will be 8 bytes at most (For UInt64) so generating a bits128 key (ie 16 bytes) is more than overkill already
let key = SymmetricKey(size: .bits128)
// Then we use the generated key to extract a random Unsigned Fixed Width Integer.
return key.withUnsafeBytes { (pointer) -> T in
// We have a pointer on random bytes generated by our class
// Let convert those bytes to T ; in order to get our number.
return pointer.bindMemory(to: T.self).baseAddress!.pointee
}
}
}
print(Lottery.frenchLoto.random())
print(Lottery.euromillion.random())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.