Skip to content

Secure Token Generator — Swift source

Generate cryptographically-secure random tokens in your browser. Pick the entropy size and format - hex, base32, base64, base62, or alphanumeric - and see the real strength in bits. Runs entirely client-side.

This is the Swift implementation — the same logic the interactive tool runs, in a shareable, citable form.

// token-generator — cryptographically-secure random tokens in hex/base32/base64/base62/... alphabets, with unbiased symbol selection and entropy/strength estimates. Swift (5.9) port of src/lib/token-generator.ts — same logic as this dir's javascript.js; the full 8-entry alphabet table, custom alphabets and injectable RNG omitted for the 80-line budget (see javascript.js / python.py). UInt32.random uses SystemRandomNumberGenerator — the cryptographically secure generator Swift uses by default.
import Foundation

/// The fixed alphabets (subset).
let alphabets = [
    "hex": "0123456789abcdef",
    "base32": "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",                     // RFC 4648
    "base64url": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
    "base62": "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
]

/// Resolve an alphabet name to its symbol string; unknown -> hex (the default).
func resolveAlphabet(_ name: String) -> String {
    alphabets[name] ?? alphabets["hex"]!
}

/// Characters needed to carry `bytes` bytes of entropy through `size` symbols.
func outputLength(_ bytes: Double, alphabetSize size: Int) -> Int {
    guard bytes >= 1, size >= 2 else { return 0 }
    return Int((bytes * 8 / log2(Double(size))).rounded(.up))
}

/// Pick alphabet[n] WITHOUT modulo bias: naive draw % size favors trailing
/// symbols whenever size does not divide the draw range (base62 etc.), so any
/// draw at or above the largest multiple of size fitting in 32 bits is
/// rejected and redrawn. The 64-redraw cap stops a broken RNG from looping
/// forever — same guard as the TS/Python reference.
func selectUnbiased(_ alphabet: String, _ n: Int) -> String {
    let symbols = Array(alphabet)
    let size = UInt32(symbols.count)
    let limit = UInt32.max / size * size
    var out = ""
    out.reserveCapacity(n)
    for _ in 0..<n {
        var x = UInt32.random(in: .min ... .max)
        var redraws = 0
        while x >= limit && redraws < 64 {
            x = UInt32.random(in: .min ... .max)
            redraws += 1
        }
        out.append(symbols[Int(x % size)])
    }
    return out
}

/// Bucket an entropy estimate (bits) into the tool's strength tiers:
/// weak <64 · fair 64-127 · strong 128-255 · very strong >=256.
func strengthLabel(_ bits: Double) -> String {
    if bits < 64 { return "weak" }
    if bits < 128 { return "fair" }
    if bits < 256 { return "strong" }
    return "very strong"
}

// Demo: the island's three showcase rows — 16-byte hex, 20-byte base62,
// 32-byte base32 — each labeled with its real strength in bits.
for (name, bytes) in [("hex", 16.0), ("base62", 20.0), ("base32", 32.0)] {
    let alphabet = resolveAlphabet(name)
    let token = selectUnbiased(alphabet, outputLength(bytes, alphabetSize: alphabet.count))
    let bits = Double(token.count) * log2(Double(alphabet.count))
    print(String(format: "%-8s %.0f bytes -> %@  (%.0f bits, %@)",
                 (name as NSString).utf8String!, bytes, token, bits, strengthLabel(bits)))
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →