import Foundation import CryptoKit // MARK: - Data ↔ Hex extension Data { /// Convert data to lowercase hex string var hexString: String { map { String(format: "%02x", $0) }.joined() } /// Initialize Data from a hex string init?(hexString: String) { let hex = hexString.lowercased() guard hex.count % 2 == 0 else { return nil } var data = Data(capacity: hex.count / 2) var index = hex.startIndex while index < hex.endIndex { let nextIndex = hex.index(index, offsetBy: 2) guard let byte = UInt8(hex[index.. Data { var data = Data(count: count) data.withUnsafeMutableBytes { ptr in _ = SecRandomCopyBytes(kSecRandomDefault, count, ptr.baseAddress!) } return data } } // MARK: - Data ↔ Base64 (Protocol Wire Format) extension Data { /// Encode to standard base64 string (matching Python's base64.b64encode) func base64EncodedString() -> String { self.base64EncodedString(options: []) } /// Decode from base64 string static func fromBase64(_ string: String) throws -> Data { // Try standard base64 first, then URL-safe if let data = Data(base64Encoded: string, options: .ignoreUnknownCharacters) { return data } throw CryptoError.invalidBase64 } } // MARK: - UInt32 Big-Endian extension UInt32 { var bigEndianData: Data { var value = self.bigEndian return Data(bytes: &value, count: 4) } } // MARK: - CryptoKit Key → Data extension Curve25519.KeyAgreement.PublicKey { var rawData: Data { Data(rawRepresentation) } } extension Curve25519.KeyAgreement.PrivateKey { var rawData: Data { Data(rawRepresentation) } } extension Curve25519.Signing.PublicKey { var rawData: Data { Data(rawRepresentation) } } extension Curve25519.Signing.PrivateKey { var rawData: Data { Data(rawRepresentation) } } // MARK: - String helpers extension String { /// Trim whitespace and newlines var trimmed: String { trimmingCharacters(in: .whitespacesAndNewlines) } } // MARK: - Dictionary merge helper extension Dictionary where Key == String, Value == Any { func string(for key: String) -> String? { self[key] as? String } func int(for key: String) -> Int? { if let i = self[key] as? Int { return i } if let s = self[key] as? String, let i = Int(s) { return i } return nil } func dict(for key: String) -> [String: Any]? { self[key] as? [String: Any] } func array(for key: String) -> [[String: Any]]? { self[key] as? [[String: Any]] } func data(for key: String) -> Data? { if let hex = self[key] as? String { return Data(hexString: hex) } return nil } func bool(for key: String) -> Bool? { if let b = self[key] as? Bool { return b } if let i = self[key] as? Int { return i != 0 } return nil } }