SPB Git

spb/os-vault Public

Self-custody, multi-chain crypto wallet for macOS. One recovery phrase, six chain families, zero API keys — nothing leaves your Mac.

Swift 96% Shell 3.4% Makefile 0.6%
2.9 KB · 112 lines swift
Raw Blame History
1import Foundation23public enum Base58 {4    static let base58Alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"56    // Encode7    public static func encode(_ data: Data) -> String {8        encode(data.bytes)9    }1011    public static func encode(_ bytes: [UInt8]) -> String {12        var bytes = bytes13        var zerosCount = 014        var length = 01516        for b in bytes {17            if b != 0 { break }18            zerosCount += 119        }2021        bytes.removeFirst(zerosCount)2223        let size = bytes.count * 138 / 100 + 12425        var base58: [UInt8] = Array(repeating: 0, count: size)26        for b in bytes {27            var carry = Int(b)28            var i = 02930            for j in 0 ... base58.count - 1 where carry != 0 || i < length {31                carry += 256 * Int(base58[base58.count - j - 1])32                base58[base58.count - j - 1] = UInt8(carry % 58)33                carry /= 5834                i += 135            }3637            assert(carry == 0)3839            length = i40        }4142        // skip leading zeros43        var zerosToRemove = 044        var str = ""45        for b in base58 {46            if b != 0 { break }47            zerosToRemove += 148        }49        base58.removeFirst(zerosToRemove)5051        while zerosCount > 0 {52            str = "\(str)1"53            zerosCount -= 154        }5556        for b in base58 {57            str = "\(str)\(base58Alphabet[String.Index(encodedOffset: Int(b))])"58        }5960        return str61    }6263    // Decode64    public static func decode(_ base58: String) -> [UInt8] {65        // remove leading and trailing whitespaces66        let string = base58.trimmingCharacters(in: CharacterSet.whitespaces)6768        guard !string.isEmpty else { return [] }6970        var zerosCount = 071        var length = 072        for c in string {73            if c != "1" { break }74            zerosCount += 175        }7677        let size = string.lengthOfBytes(using: String.Encoding.utf8)78        var base58: [UInt8] = Array(repeating: 0, count: size)79        for c in string where c != " " {80            // search for base58 character81            guard let base58Index = base58Alphabet.firstIndex(of: c) else { return [] }8283            var carry = base58Index.encodedOffset84            var i = 085            for j in 0 ... base58.count where carry != 0 || i < length {86                carry += 58 * Int(base58[base58.count - j - 1])87                base58[base58.count - j - 1] = UInt8(carry % 256)88                carry /= 25689                i += 190            }9192            assert(carry == 0)93            length = i94        }9596        // skip leading zeros97        var zerosToRemove = 09899        for b in base58 {100            if b != 0 { break }101            zerosToRemove += 1102        }103        base58.removeFirst(zerosToRemove)104105        var result: [UInt8] = Array(repeating: 0, count: zerosCount)106        for b in base58 {107            result.append(b)108        }109        return result110    }111}112