This repository has been archived by the owner on May 10, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 440
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
97 additions
and
53 deletions.
There are no files selected for viewing
150 changes: 97 additions & 53 deletions
150
Client/Frontend/Browser/User Scripts/ARC4RandomNumberGenerator.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,110 @@ | ||
// Copyright 2022 The Brave Authors. All rights reserved. | ||
// This Source Code Form is subject to the terms of the Mozilla Public | ||
// License, v. 2.0. If a copy of the MPL was not distributed with this | ||
// file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
// ===-- Random.swift ------------------------------------------*- swift -*-===// | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors | ||
// Licensed under Apache License v2.0 with Runtime Library Exception | ||
// | ||
// See https://swift.org/LICENSE.txt for license information | ||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors | ||
// | ||
// ===----------------------------------------------------------------------===// | ||
// | ||
// A (pseudo-)random number generation library. The library separates concerns | ||
// into engines which generate random bytes and distributions which use an | ||
// engine to generate values from some statistical distribution. | ||
// | ||
// ===----------------------------------------------------------------------===// | ||
|
||
import Foundation | ||
|
||
/// A seeded random number generator taken from GameplayKit which can be found here: | ||
/// https://github.com/apple/swift/blob/bc8f9e61d333b8f7a625f74d48ef0b554726e349/stdlib/public/TensorFlow/Random.swift | ||
public struct ARC4RandomNumberGenerator: RandomNumberGenerator { | ||
private var state: [UInt8] = Array(0...255) | ||
private var iPos: UInt8 = 0 | ||
private var jPos: UInt8 = 0 | ||
|
||
public init<T: BinaryInteger>(seed: T) { | ||
var newSeed: [UInt8] = [] | ||
// This `RandomNumberGenerator` is taken from Apple's `TensorFlow` which can be found here: | ||
// https://github.com/apple/swift/blob/bc8f9e61d333b8f7a625f74d48ef0b554726e349/stdlib/public/TensorFlow/Random.swift | ||
|
||
for i in 0..<(seed.bitWidth / UInt8.bitWidth) { | ||
newSeed.append(UInt8(truncatingIfNeeded: seed >> (UInt8.bitWidth * i))) | ||
} | ||
import Foundation | ||
|
||
self.init(seed: newSeed) | ||
} | ||
/// A type that provides seedable deterministic pseudo-random data. | ||
/// | ||
/// A SeedableRandomNumberGenerator can be used anywhere where a | ||
/// RandomNumberGenerator would be used. It is useful when the pseudo-random | ||
/// data needs to be reproducible across runs. | ||
/// | ||
/// Conforming to the SeedableRandomNumberGenerator Protocol | ||
/// ======================================================== | ||
/// | ||
/// To make a custom type conform to the `SeedableRandomNumberGenerator` | ||
/// protocol, implement the `init(seed: [UInt8])` initializer, as well as the | ||
/// requirements for `RandomNumberGenerator`. The values returned by `next()` | ||
/// must form a deterministic sequence that depends only on the seed provided | ||
/// upon initialization. | ||
public protocol SeedableRandomNumberGenerator: RandomNumberGenerator { | ||
init(seed: [UInt8]) | ||
init<T: BinaryInteger>(seed: T) | ||
} | ||
|
||
/// Initialize ARC4RandomNumberGenerator using an array of UInt8. The array | ||
/// must have length between 1 and 256 inclusive. | ||
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") | ||
var j: UInt8 = 0 | ||
for i: UInt8 in 0...255 { | ||
j &+= S(i) &+ seed[Int(i) % seed.count] | ||
swapAt(i, j) | ||
} | ||
extension SeedableRandomNumberGenerator { | ||
public init<T: BinaryInteger>(seed: T) { | ||
var newSeed: [UInt8] = [] | ||
for i in 0..<seed.bitWidth / UInt8.bitWidth { | ||
newSeed.append(UInt8(truncatingIfNeeded: seed >> (UInt8.bitWidth * i))) | ||
} | ||
self.init(seed: newSeed) | ||
} | ||
} | ||
|
||
/// Produce the next random UInt64 from the stream, and advance the internal state. | ||
public mutating func next() -> UInt64 { | ||
var result: UInt64 = 0 | ||
for _ in 0..<UInt64.bitWidth / UInt8.bitWidth { | ||
result <<= UInt8.bitWidth | ||
result += UInt64(nextByte()) | ||
} | ||
/// An implementation of `SeedableRandomNumberGenerator` using ARC4. | ||
/// | ||
/// ARC4 is a stream cipher that generates a pseudo-random stream of bytes. This | ||
/// PRNG uses the seed as its key. | ||
/// | ||
/// ARC4 is described in Schneier, B., "Applied Cryptography: Protocols, | ||
/// Algorithms, and Source Code in C", 2nd Edition, 1996. | ||
/// | ||
/// An individual generator is not thread-safe, but distinct generators do not | ||
/// share state. The random data generated is of high-quality, but is not | ||
/// suitable for cryptographic applications. | ||
public struct ARC4RandomNumberGenerator: SeedableRandomNumberGenerator { | ||
public static var global = ARC4RandomNumberGenerator(seed: UInt32(time(nil))) | ||
var state: [UInt8] = Array(0...255) | ||
var iPos: UInt8 = 0 | ||
var jPos: UInt8 = 0 | ||
|
||
print(result) | ||
return result | ||
/// Initialize ARC4RandomNumberGenerator using an array of UInt8. The array | ||
/// must have length between 1 and 256 inclusive. | ||
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") | ||
var j: UInt8 = 0 | ||
for i: UInt8 in 0...255 { | ||
j &+= S(i) &+ seed[Int(i) % seed.count] | ||
swapAt(i, j) | ||
} | ||
} | ||
|
||
/// Helper to access the state. | ||
private func S(_ index: UInt8) -> UInt8 { | ||
return state[Int(index)] | ||
/// Produce the next random UInt64 from the stream, and advance the internal | ||
/// state. | ||
public mutating func next() -> UInt64 { | ||
var result: UInt64 = 0 | ||
for _ in 0..<UInt64.bitWidth / UInt8.bitWidth { | ||
result <<= UInt8.bitWidth | ||
result += UInt64(nextByte()) | ||
} | ||
return result | ||
} | ||
|
||
/// Helper to swap elements of the state. | ||
private mutating func swapAt(_ i: UInt8, _ j: UInt8) { | ||
state.swapAt(Int(i), Int(j)) | ||
} | ||
/// Helper to access the state. | ||
private func S(_ index: UInt8) -> UInt8 { | ||
return state[Int(index)] | ||
} | ||
|
||
/// 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)) | ||
} | ||
/// 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)) | ||
} | ||
} |