mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			74 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Swift
		
	
			
		
		
	
	
			74 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Swift
		
	
| // Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
 | |
| //
 | |
| // Note: This was taken from TensorFlow's Random:
 | |
| // https://github.com/apple/swift/blob/bc8f9e61d333b8f7a625f74d48ef0b554726e349/stdlib/public/TensorFlow/Random.swift
 | |
| //
 | |
| // the complex approach is needed due to an issue with Swift's randomElement(using:)
 | |
| // generation (see https://stackoverflow.com/a/64897775 for more info)
 | |
| 
 | |
| import Foundation
 | |
| 
 | |
| public struct ARC4RandomNumberGenerator: RandomNumberGenerator {
 | |
|     var state: [UInt8] = Array(0...255)
 | |
|     var iPos: UInt8 = 0
 | |
|     var jPos: UInt8 = 0
 | |
|     
 | |
|     public init<T: BinaryInteger>(seed: T) {
 | |
|         self.init(
 | |
|             seed: (0..<(UInt64.bitWidth / UInt64.bitWidth)).map { index in
 | |
|                 UInt8(truncatingIfNeeded: seed >> (UInt8.bitWidth * index))
 | |
|             }
 | |
|         )
 | |
|     }
 | |
|     
 | |
|     public init(seed: [UInt8]) {
 | |
|         precondition(seed.count > 0, "Length of seed must be positive")
 | |
|         precondition(seed.count <= 256, "Length of seed must be at most 256")
 | |
|         
 | |
|         // Note: Have to use a for loop instead of a 'forEach' otherwise
 | |
|         // it doesn't work properly (not sure why...)
 | |
|         var j: UInt8 = 0
 | |
|         for i: UInt8 in 0...255 {
 | |
|           j &+= S(i) &+ seed[Int(i) % seed.count]
 | |
|           swapAt(i, j)
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /// Produce the next random UInt64 from the stream, and advance the internal state
 | |
|     public mutating func next() -> UInt64 {
 | |
|         // Note: Have to use a for loop instead of a 'forEach' otherwise
 | |
|         // it doesn't work properly (not sure why...)
 | |
|         var result: UInt64 = 0
 | |
|         for _ in 0..<UInt64.bitWidth / UInt8.bitWidth {
 | |
|           result <<= UInt8.bitWidth
 | |
|           result += UInt64(nextByte())
 | |
|         }
 | |
|         
 | |
|         return result
 | |
|     }
 | |
|     
 | |
|     /// Helper to access the state
 | |
|     private func S(_ index: UInt8) -> UInt8 {
 | |
|         return state[Int(index)]
 | |
|     }
 | |
|     
 | |
|     /// Helper to swap elements of the state
 | |
|     private mutating func swapAt(_ i: UInt8, _ j: UInt8) {
 | |
|         state.swapAt(Int(i), Int(j))
 | |
|     }
 | |
| 
 | |
|     /// Generates the next byte in the keystream.
 | |
|     private mutating func nextByte() -> UInt8 {
 | |
|         iPos &+= 1
 | |
|         jPos &+= S(iPos)
 | |
|         swapAt(iPos, jPos)
 | |
|         return S(S(iPos) &+ S(jPos))
 | |
|     }
 | |
| }
 | |
| 
 | |
| public extension ARC4RandomNumberGenerator {
 | |
|     mutating func nextBytes(count: Int) -> [UInt8] {
 | |
|         (0..<count).map { _ in nextByte() }
 | |
|     }
 | |
| }
 |