76 lines
2.3 KiB
Swift
76 lines
2.3 KiB
Swift
import Foundation
|
|
|
|
/// Base58 with the XRP Ledger alphabet and Base58Check helpers.
|
|
enum XRPBase58 {
|
|
static let alphabet: [Character] = Array("rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz")
|
|
|
|
private static let valueOf: [Character: Int] = {
|
|
var map: [Character: Int] = [:]
|
|
for (index, character) in alphabet.enumerated() { map[character] = index }
|
|
return map
|
|
}()
|
|
|
|
static func encode(_ bytes: [UInt8]) -> String {
|
|
var zeros = 0
|
|
for byte in bytes {
|
|
if byte == 0 { zeros += 1 } else { break }
|
|
}
|
|
|
|
var digits: [Int] = []
|
|
for byte in bytes[zeros...] {
|
|
var carry = Int(byte)
|
|
for index in digits.indices {
|
|
carry += digits[index] << 8
|
|
digits[index] = carry % 58
|
|
carry /= 58
|
|
}
|
|
while carry > 0 {
|
|
digits.append(carry % 58)
|
|
carry /= 58
|
|
}
|
|
}
|
|
|
|
var output = String(repeating: String(alphabet[0]), count: zeros)
|
|
for digit in digits.reversed() { output.append(alphabet[digit]) }
|
|
return output
|
|
}
|
|
|
|
static func decode(_ string: String) throws -> [UInt8] {
|
|
let characters = Array(string)
|
|
var zeros = 0
|
|
for character in characters {
|
|
if character == alphabet[0] { zeros += 1 } else { break }
|
|
}
|
|
|
|
var bytes: [Int] = []
|
|
for character in characters[zeros...] {
|
|
guard let value = valueOf[character] else { throw XRPError.invalidBase58 }
|
|
var carry = value
|
|
for index in bytes.indices {
|
|
carry += bytes[index] * 58
|
|
bytes[index] = carry & 0xff
|
|
carry >>= 8
|
|
}
|
|
while carry > 0 {
|
|
bytes.append(carry & 0xff)
|
|
carry >>= 8
|
|
}
|
|
}
|
|
|
|
return [UInt8](repeating: 0, count: zeros) + bytes.reversed().map { UInt8($0) }
|
|
}
|
|
|
|
static func checkEncode(version: [UInt8], payload: [UInt8]) -> String {
|
|
let body = version + payload
|
|
return encode(body + XRPHash.checksum(body))
|
|
}
|
|
|
|
static func checkDecode(_ string: String, versionLength: Int) throws -> [UInt8] {
|
|
let decoded = try decode(string)
|
|
guard decoded.count > versionLength + 4 else { throw XRPError.invalidAddress }
|
|
let body = Array(decoded[0..<(decoded.count - 4)])
|
|
let checksum = Array(decoded[(decoded.count - 4)...])
|
|
guard XRPHash.checksum(body) == checksum else { throw XRPError.invalidAddress }
|
|
return Array(body[versionLength...])
|
|
}
|
|
} |