Skip to content

Commit bab86ca

Browse files
refactor: random bytes generation; data and string extensions update (#791)
* Update HexDecodable+Extensions.swift * Update Data+Extension.swift * Update String+Extension.swift * chore: refactoring + documentation for Data.fromHex function * updates as per conversations * chore: updated docs for randomBytes + minor refactoring * chore: fixed typo in Data+Extension.swift * chore: lint issue fixed * add string spit test * Revert "add string spit test" github issue This reverts commit e8a5e2b. --------- Co-authored-by: Jenea Vranceanu <jeneavranceanu@gmail.com> Co-authored-by: Jenea Vranceanu <36865532+JeneaVranceanu@users.noreply.github.com>
1 parent 2d4bffd commit bab86ca

File tree

4 files changed

+63
-28
lines changed

4 files changed

+63
-28
lines changed

Sources/Web3Core/EthereumNetwork/Utility/HexDecodable+Extensions.swift

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,17 @@ extension BigInt: LiteralInitiableFromString { }
1717
extension BigUInt: LiteralInitiableFromString { }
1818

1919
extension Data: LiteralInitiableFromString {
20+
/// Converts hexadecimal string representation of some bytes into actual bytes.
21+
/// Notes:
22+
/// - empty string will return `nil`;
23+
/// - empty hex string, meaning it's equal to `"0x"`, will return empty `Data` object.
24+
/// - Parameter hex: bytes represented as string.
25+
/// - Returns: optional raw bytes.
2026
public static func fromHex(_ hex: String) -> Data? {
21-
let string = hex.lowercased().stripHexPrefix()
22-
let array = [UInt8](hex: string)
23-
if array.count == 0 {
24-
if hex == "0x" || hex == "" {
25-
return Data()
26-
} else {
27-
return nil
28-
}
29-
}
30-
return Data(array)
27+
let hex = hex.lowercased().trim()
28+
guard !hex.isEmpty else { return nil }
29+
guard hex != "0x" else { return Data() }
30+
let bytes = [UInt8](hex: hex.stripHexPrefix())
31+
return bytes.isEmpty ? nil : Data(bytes)
3132
}
3233
}

Sources/Web3Core/Utility/Data+Extension.swift

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55

66
import Foundation
77

8-
extension Data {
8+
public extension Data {
9+
910
init<T>(fromArray values: [T]) {
1011
let values = values
1112
let ptrUB = values.withUnsafeBufferPointer { (ptr: UnsafeBufferPointer) in return ptr }
@@ -33,32 +34,34 @@ extension Data {
3334
return difference == UInt8(0x00)
3435
}
3536

36-
public static func zero(_ data: inout Data) {
37+
static func zero(_ data: inout Data) {
3738
let count = data.count
3839
data.withUnsafeMutableBytes { (body: UnsafeMutableRawBufferPointer) in
3940
body.baseAddress?.assumingMemoryBound(to: UInt8.self).initialize(repeating: 0, count: count)
4041
}
4142
}
4243

43-
public static func randomBytes(length: Int) -> Data? {
44-
for _ in 0...1024 {
45-
var data = Data(repeating: 0, count: length)
46-
let result = data.withUnsafeMutableBytes { (body: UnsafeMutableRawBufferPointer) -> Int32? in
47-
if let bodyAddress = body.baseAddress, body.count > 0 {
48-
let pointer = bodyAddress.assumingMemoryBound(to: UInt8.self)
49-
return SecRandomCopyBytes(kSecRandomDefault, length, pointer)
50-
} else {
51-
return nil
52-
}
53-
}
54-
if let notNilResult = result, notNilResult == errSecSuccess {
55-
return data
56-
}
44+
/**
45+
Generates an array of random bytes of the specified length.
46+
This function uses `SecRandomCopyBytes` to generate random bytes returning it as a `Data` object.
47+
If an error occurs during random bytes generation, the function returns `nil`.
48+
Error occurs only if `SecRandomCopyBytes` returns status that is not `errSecSuccess`.
49+
See [all status codes](https://developer.apple.com/documentation/security/1542001-security_framework_result_codes) for possible error reasons.
50+
Note: in v4 of web3swift this function will be deprecated and a new implementation will be provided that will throw occurred error.
51+
- Parameter length: The number of random bytes to generate.
52+
53+
- Returns: optional `Data` object containing the generated random bytes, or `nil` if an error occurred during generation.
54+
*/
55+
static func randomBytes(length: Int) -> Data? {
56+
var entropyBytes = [UInt8](repeating: 0, count: length)
57+
let status = SecRandomCopyBytes(kSecRandomDefault, entropyBytes.count, &entropyBytes)
58+
guard status == errSecSuccess else {
59+
return nil
5760
}
58-
return nil
61+
return Data(entropyBytes)
5962
}
6063

61-
public func bitsInRange(_ startingBit: Int, _ length: Int) -> UInt64? { // return max of 8 bytes for simplicity, non-public
64+
func bitsInRange(_ startingBit: Int, _ length: Int) -> UInt64? { // return max of 8 bytes for simplicity, non-public
6265
if startingBit + length / 8 > self.count, length > 64, startingBit > 0, length >= 1 { return nil }
6366
let bytes = self[(startingBit/8) ..< (startingBit+length+7)/8]
6467
let padding = Data(repeating: 0, count: 8 - bytes.count)

Sources/Web3Core/Utility/String+Extension.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,26 @@ extension String {
135135
func trim() -> String {
136136
trimmingCharacters(in: .whitespacesAndNewlines)
137137
}
138+
139+
/// Splits a string into groups of `every` n characters, grouping from left-to-right by default. If `backwards` is true, right-to-left.
140+
public func split(every: Int, backwards: Bool = false) -> [String] {
141+
var result = [String]()
142+
143+
for i in stride(from: 0, to: self.count, by: every) {
144+
switch backwards {
145+
case true:
146+
let endIndex = self.index(self.endIndex, offsetBy: -i)
147+
let startIndex = self.index(endIndex, offsetBy: -every, limitedBy: self.startIndex) ?? self.startIndex
148+
result.insert(String(self[startIndex..<endIndex]), at: 0)
149+
case false:
150+
let startIndex = self.index(self.startIndex, offsetBy: i)
151+
let endIndex = self.index(startIndex, offsetBy: every, limitedBy: self.endIndex) ?? self.endIndex
152+
result.append(String(self[startIndex..<endIndex]))
153+
}
154+
}
155+
156+
return result
157+
}
138158
}
139159

140160
extension Character {

Tests/web3swiftTests/localTests/UncategorizedTests.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,17 @@ class UncategorizedTests: XCTestCase {
5151
XCTAssert(biguint == BigUInt("126978086000000000"))
5252
}
5353

54+
func testStringSplit() {
55+
XCTAssertEqual("abcdefgh".split(every: 3), ["abc", "def", "gh"])
56+
XCTAssertEqual("abcdefgh".split(every: 3, backwards: true), ["ab", "cde", "fgh"])
57+
58+
XCTAssertEqual("abcdefgh".split(every: 10), ["abcdefgh"])
59+
XCTAssertEqual("".split(every: 3), [])
60+
61+
XCTAssertEqual("abcdefgh".split(every: 1), ["a", "b", "c", "d", "e", "f", "g", "h"])
62+
XCTAssertEqual("abcdefgh".split(every: 1, backwards: true), ["a", "b", "c", "d", "e", "f", "g", "h"]) // should be the same as from the front
63+
}
64+
5465
func testBloom() throws {
5566
let positive = [
5667
"testtest",

0 commit comments

Comments
 (0)