mirror of
https://github.com/luxfi/safe-ios.git
synced 2026-10-30 15:19:20 +00:00
161 lines
4.3 KiB
Swift
161 lines
4.3 KiB
Swift
//
|
|
// Copyright © 2020 Gnosis Ltd. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
// https://github.com/matter-labs/web3swift
|
|
|
|
struct Base58 {
|
|
static let base58Alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
|
|
|
// Encode
|
|
static func base58FromBytes(_ bytes: [UInt8]) -> String {
|
|
var bytes = bytes
|
|
var zerosCount = 0
|
|
var length = 0
|
|
|
|
for b in bytes {
|
|
if b != 0 { break }
|
|
zerosCount += 1
|
|
}
|
|
|
|
bytes.removeFirst(zerosCount)
|
|
|
|
let size = bytes.count * 138 / 100 + 1
|
|
|
|
var base58: [UInt8] = Array(repeating: 0, count: size)
|
|
for b in bytes {
|
|
var carry = Int(b)
|
|
var i = 0
|
|
|
|
for j in 0...base58.count-1 where carry != 0 || i < length {
|
|
carry += 256 * Int(base58[base58.count - j - 1])
|
|
base58[base58.count - j - 1] = UInt8(carry % 58)
|
|
carry /= 58
|
|
i += 1
|
|
}
|
|
|
|
assert(carry == 0)
|
|
|
|
length = i
|
|
}
|
|
|
|
// skip leading zeros
|
|
var zerosToRemove = 0
|
|
var str = ""
|
|
for b in base58 {
|
|
if b != 0 { break }
|
|
zerosToRemove += 1
|
|
}
|
|
base58.removeFirst(zerosToRemove)
|
|
|
|
while 0 < zerosCount {
|
|
str = "\(str)1"
|
|
zerosCount -= 1
|
|
}
|
|
|
|
for b in base58 {
|
|
//str = "\(str)\(base58Alphabet[String.Index(encodedOffset: Int(b))])"
|
|
str = "\(str)\(base58Alphabet[String.Index(utf16Offset: Int(b), in: base58Alphabet)])"
|
|
}
|
|
|
|
return str
|
|
}
|
|
|
|
// Decode
|
|
static func bytesFromBase58(_ base58: String) -> [UInt8] {
|
|
// remove leading and trailing whitespaces
|
|
let string = base58.trimmingCharacters(in: CharacterSet.whitespaces)
|
|
|
|
guard !string.isEmpty else { return [] }
|
|
|
|
var zerosCount = 0
|
|
var length = 0
|
|
for c in string {
|
|
if c != "1" { break }
|
|
zerosCount += 1
|
|
}
|
|
|
|
let size = string.lengthOfBytes(using: String.Encoding.utf8) * 733 / 1000 + 1 - zerosCount
|
|
var base58: [UInt8] = Array(repeating: 0, count: size)
|
|
for c in string where c != " " {
|
|
// search for base58 character
|
|
guard let base58Index = base58Alphabet.firstIndex(of: c) else { return [] }
|
|
|
|
// var carry = base58Index.encodedOffset
|
|
var carry = base58Index.utf16Offset(in: base58Alphabet)
|
|
var i = 0
|
|
for j in 0...base58.count where carry != 0 || i < length {
|
|
carry += 58 * Int(base58[base58.count - j - 1])
|
|
base58[base58.count - j - 1] = UInt8(carry % 256)
|
|
carry /= 256
|
|
i += 1
|
|
}
|
|
|
|
assert(carry == 0)
|
|
length = i
|
|
}
|
|
|
|
// skip leading zeros
|
|
var zerosToRemove = 0
|
|
|
|
for b in base58 {
|
|
if b != 0 { break }
|
|
zerosToRemove += 1
|
|
}
|
|
base58.removeFirst(zerosToRemove)
|
|
|
|
var result: [UInt8] = Array(repeating: 0, count: zerosCount)
|
|
for b in base58 {
|
|
result.append(b)
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
|
|
extension Array where Element == UInt8 {
|
|
public var base58EncodedString: String {
|
|
guard !self.isEmpty else { return "" }
|
|
return Base58.base58FromBytes(self)
|
|
}
|
|
|
|
public var base58CheckEncodedString: String {
|
|
var bytes = self
|
|
let checksum = [UInt8](bytes.sha256().sha256()[0..<4])
|
|
|
|
bytes.append(contentsOf: checksum)
|
|
|
|
return Base58.base58FromBytes(bytes)
|
|
}
|
|
}
|
|
|
|
extension String {
|
|
public var base58EncodedString: String {
|
|
return [UInt8](utf8).base58EncodedString
|
|
}
|
|
|
|
public var base58DecodedData: Data? {
|
|
let bytes = Base58.bytesFromBase58(self)
|
|
return Data(bytes)
|
|
}
|
|
|
|
public var base58CheckDecodedData: Data? {
|
|
guard let bytes = self.base58CheckDecodedBytes else { return nil }
|
|
return Data(bytes)
|
|
}
|
|
|
|
public var base58CheckDecodedBytes: [UInt8]? {
|
|
var bytes = Base58.bytesFromBase58(self)
|
|
guard 4 <= bytes.count else { return nil }
|
|
|
|
let checksum = [UInt8](bytes[bytes.count-4..<bytes.count])
|
|
bytes = [UInt8](bytes[0..<bytes.count-4])
|
|
|
|
let calculatedChecksum = [UInt8](bytes.sha256().sha256()[0...3])
|
|
if checksum != calculatedChecksum { return nil }
|
|
|
|
return bytes
|
|
}
|
|
}
|