The official way to do this is with a version 5 UUID (RFC 4122 Section 4.3):
4.3 Algorithm for Creating a Name-Based UUID
The version 3 or 5 UUID is meant for generating UUIDs from "names"
that are drawn from, and unique within, some "name space".
The process is to hash your string, and then insert that into a UUID. I'm going to carefully follow the spec here, but I'll mark the parts you could ignore and it'll still work correctly.
As matt notes, you can just use a SHA directly if you just need a hash. But if your system actually requires a UUID, this is how you do it.
- Define a namespace (this isn't fully necessary, but it will make sure your UUIDs are globally unique):
let namespace = "com.example.mygreatsystem:"
- Combine that with your string
let inputString = "arandomstring"
let fullString = namespace + inputString
- Hash the values. The UUID v5 spec specifically calls for SHA-1, but feel free to use SHA-256 (SHA-2) here instead. There's no actual security concern with using SHA-1 here, but it's good practice to move to SHA-2 whenever you can.
import CryptoKit
let hash = Insecure.SHA1.hash(data: Data(fullString.utf8)) // SHA-1 by spec
or
let hash = SHA256.hash(data: Data(fullString.utf8)) // SHA-2 is generally better
- Take the top 128-bits of data. (It is safe to extract any subset of bits from a SHA-1 or SHA-2 hash. Each bit is "effectively random.")
var truncatedHash = Array(hash.prefix(16))
- Correctly set the version and variant bits. This doesn't really matter for most uses. I've never encountered a system that actually parses the UUID metadata. But it's part of the spec. And if you use v4 random UUIDs for future records (which are the "normal" UUIDs for almost every system today), then this would allow you to distinguish which were created by hashing and which were random if that mattered for any reason. See UUIDTools for a nice visual introduction to the format.
truncatedHash[6] &= 0x0F // Clear version field
truncatedHash[6] |= 0x50 // Set version to 5
truncatedHash[8] &= 0x3F // Clear variant field
truncatedHash[8] |= 0x80 // Set variant to DCE 1.1
- And finally, compute your UUID:
let uuidString = NSUUID(uuidBytes: truncatedHash).uuidString