Skip to content

Instantly share code, notes, and snippets.

@AlexeyRaga
Last active August 16, 2021 02:15
Show Gist options
  • Save AlexeyRaga/eba296868379a9225f4b20b30e65e822 to your computer and use it in GitHub Desktop.
Save AlexeyRaga/eba296868379a9225f4b20b30e65e822 to your computer and use it in GitHub Desktop.
open System
open System.Security.Cryptography
open System.Text
[<RequireQualifiedAccess>]
module Guid =
let private hashProvider = SHA1.Create()
let private sha1 (bytes: byte array) = hashProvider.ComputeHash(bytes)
let inline private swapOrder arr =
let inline swapBytes a b (arr: byte array) =
let t = arr.[a]
arr.[a] <- arr.[b]
arr.[b] <- t
arr
// Microsoft uses (Int32, Int16, Int16, Byte[8]) structure to represent Guid.
// Which makes representation of first 8 bytes in a "wrong" order
// (because Int32 and Int16 are little-endian in dotnet)
arr
|> swapBytes 0 3
|> swapBytes 1 2
|> swapBytes 4 5
|> swapBytes 6 7
/// This function implements RFC 4122 for UUID v5.
///
/// GUID v5 is used for deterministically creating "namespaced" unique identifiers.
/// Which reads as "An identifier for a given name within a given namespace".
let createNamespaced (namespaceId: Guid) (name: byte array) =
let ns = namespaceId.ToByteArray() |> swapOrder
let bytes = ns |> Array.append name |> sha1 |> Array.take 16
// indicate v5 UUID: set bits 12-15
bytes.[6] <- (bytes.[6] &&& 0x0Fuy) ||| 0x50uy
// ser bits 6-7 to 0 and 1
bytes.[8] <- (bytes.[8] &&& 0x3Fuy) ||| 0x80uy
bytes |> swapOrder |> Guid
let createNamespacedForGuid (namespaceId: Guid) (value: Guid) =
value.ToByteArray()
|> swapOrder
|> createNamespaced namespaceId
let createNamespacedForName (namespaceId: Guid) (name: string) =
Encoding.UTF8.GetBytes(name)
|> createNamespaced namespaceId
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment