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
		
	
| 
											2 years ago
										 | // 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() } | ||
|  |     } | ||
|  | } |