Skip to content

Commit 3f41706

Browse files
committedAug 18, 2017
Add CharSet bytesNeeded
1 parent 499dea3 commit 3f41706

File tree

6 files changed

+46
-23
lines changed

6 files changed

+46
-23
lines changed
 

‎EntropyString.podspec

+7-7
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22

33
Pod::Spec.new do |s|
44
s.name = "EntropyString"
5-
s.version = "2.0.1"
5+
s.version = "2.1.0"
66
s.summary = "Efficiently generate cryptographically strong random strings of specified entropy from various character sets."
77

8-
s.description = <<-DESC
8+
s.description = <<-DESC
99
Efficiently generate cryptographically strong and secure random strings of specified entropy from various character sets for use when probabilisticly unique string identifiers are needed. Entropy is calculated from a total number of strings and acceptable risk of a repeat.
1010
DESC
1111

12-
s.homepage = "https://github.com/#{s.name}/#{s.name}-Swift"
13-
s.license = { :type => "MIT", :file => "LICENSE" }
14-
s.authors = { "knoxen" => "paul@knoxen.com", "dingo sky" => "paul@dingosky.com" }
15-
s.social_media_url = "http://twitter.com/knoxen"
12+
s.homepage = "https://github.com/EntropyString/EntropyString-Swift"
13+
s.license = { :type => "MIT", :file => "LICENSE" }
14+
s.authors = { "knoxen" => "paul@knoxen.com", "dingo sky" => "paul@dingosky.com" }
15+
s.social_media_url = "http://twitter.com/knoxen"
1616

1717
s.ios.deployment_target = "9.0"
1818
s.osx.deployment_target = "10.11"
@@ -21,7 +21,7 @@ Efficiently generate cryptographically strong and secure random strings of speci
2121

2222
s.source = { :git => "https://github.com/EntropyString/EntropyString-Swift.git", :tag => "#{s.version}" }
2323

24-
s.source_files = "Sources/**/*.swift"
24+
s.source_files = "Sources/*.swift"
2525
# s.public_header_files = "#{s.name}/{s.name}.h"
2626

2727
end

‎Sources/Bytes.swift

+6-9
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@
2626
//
2727
import Foundation
2828

29-
public struct Bytes {
29+
internal struct Bytes {
3030
#if os(Linux)
3131
// On first use will attempt to load `arc4random_buf`
3232
private typealias Arc4Random_Buf = @convention(c) (ImplicitlyUnwrappedOptional<UnsafeMutableRawPointer>, Int) -> ()
3333
private var arc4random_buf: Arc4Random_Buf?
34-
public static var instance = Bytes()
34+
private static var instance = Bytes()
3535

3636
private init() {
3737
if let handle = dlopen(nil, RTLD_NOW), let result = dlsym(handle, "arc4random_buf") {
@@ -42,21 +42,18 @@ public struct Bytes {
4242

4343
/// Generates random bytes
4444
///
45-
/// The number of bytes returned is sufficient to generate _count_ characters from the `charSet`.
45+
/// The number of bytes returned is sufficient to generate a string with `bits` of entropy using `CharSet`
4646
///
47-
/// - parameter count: The number of characters that can be generated.
47+
/// - parameter bits: Entropy bits
4848
/// - paramater charSet: The character set that will be used.
4949
/// - parameter secRand: On Apple OSes, if _secRand_ is `true`, attempt to use `SecRandomCopyBytes` to
5050
/// generate random bytes; if `false` use `arc4random_buf`. This parameter is ignored on Linux OS.
5151
///
5252
/// - return: Random bytes. On Apple OSes, if _secRand_ is passed as `true`, the value on return
5353
/// indicates whether `SecRandomCopyBytes` (`true`) or `arc4random_buf` (`false`) was used.
5454
///
55-
static func random(_ count: UInt, _ entropyBits: UInt8, _ secRand: inout Bool) -> [UInt8] {
56-
// Each slice forms a chars and requires entropy per char bits
57-
let bytesPerSlice = Double(entropyBits) / Double(Entropy.bitsPerByte)
58-
59-
let bytesNeeded = Int(ceil(Double(count) * bytesPerSlice))
55+
static func random(_ bits: Float, _ charSet: CharSet, _ secRand: inout Bool) -> [UInt8] {
56+
let bytesNeeded = charSet.bytesNeeded(bits: bits)
6057
var bytes = [UInt8](repeating: 0, count: bytesNeeded)
6158

6259
#if os(Linux)

‎Sources/CharSet.swift

+6-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,12 @@ public struct CharSet {
5959
ndxFn = CharSet.ndxFnForNonDivisor(bitsPerChar)
6060
}
6161
}
62-
62+
63+
public func bytesNeeded(bits: Float) -> Int {
64+
let count = ceil(bits / Float(bitsPerChar))
65+
return Int(ceil(count * Float(bitsPerChar) / Float(Entropy.bitsPerByte)))
66+
}
67+
6368
/// Determines index into `CharSet` characters when base is a multiple of 8.
6469
///
6570
/// Each `slice` of bits is used to create a single character. A `chunk` is the number of

‎Sources/Random.swift

+6-5
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,12 @@ public class Random {
9696
/// If _secRand_ is passed in as `true`, the value of _secRand_ on return indicates whether
9797
/// `SecRandomCopyBytes` (`true`) or `arc4random_buf` (`false`) was used.
9898
public func string(bits: Float, secRand: inout Bool) -> String {
99-
let count: UInt = UInt(ceil(bits / Float(charSet.bitsPerChar)))
100-
guard 0 < count else { return "" }
99+
guard 0 < bits else { return "" }
101100

102-
// genBytes sets secRand
103-
let bytes = Bytes.random(count, charSet.bitsPerChar, &secRand)
101+
// `Bytes.random` sets `secRand`
102+
let bytes = Bytes.random(bits, charSet, &secRand)
104103

105-
// genBytes ensures enough bytes so this call will not fail
104+
// `Bytes.random` ensures enough bytes so this call will not fail
106105
return try! string(bits: bits, using: bytes)
107106
}
108107

@@ -143,6 +142,8 @@ public class Random {
143142
return string
144143
}
145144

145+
// MARK: - Private
146+
146147
/// Gets a character from the current `CharSet` characters.
147148
///
148149
/// - parameter ndx: The index of the character

‎Tests/EntropyStringTests/CharSetTests.swift

+20
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,27 @@ class CharSetTests: XCTestCase {
8787
}
8888
}
8989
}
90+
91+
func testBytesNeeded() {
92+
let doTest: (CharSet, Float) -> () = { (charSet: CharSet, bits: Float) -> () in
93+
let bytesNeeded = charSet.bytesNeeded(bits: bits)
94+
let atLeast = Int(ceil(bits / Float(Entropy.bitsPerByte)))
95+
XCTAssertTrue(atLeast <= bytesNeeded)
96+
let atMost = atLeast + 1
97+
XCTAssertTrue(bytesNeeded <= atMost)
98+
}
9099

100+
let charSets = [.charSet64, .charSet32, .charSet16, .charSet8, .charSet4, .charSet2] as [CharSet]
101+
for charSet in charSets {
102+
for bits in 0 ... 10 {
103+
doTest(charSet, Float(bits))
104+
}
105+
for bits in stride(from: 12, through: 132, by: 5) {
106+
doTest(charSet, Float(bits))
107+
}
108+
}
109+
}
110+
91111
func testStatics() {
92112
XCTAssertNotNil(CharSet.charSet64)
93113
XCTAssertNotNil(CharSet.charSet32)

‎Tests/EntropyStringTests/RandomTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import XCTest
1111

1212
class RandomTests: XCTestCase {
1313
var random: Random!
14-
var charSets = [.charSet64, .charSet32, .charSet16, .charSet8, .charSet4, .charSet2] as [CharSet]
14+
let charSets = [.charSet64, .charSet32, .charSet16, .charSet8, .charSet4, .charSet2] as [CharSet]
1515

1616
func testInit() {
1717
let random = Random()

0 commit comments

Comments
 (0)
Failed to load comments.