Uniq.UUIDv47 (Uniq v0.7.0)

Copy Markdown View Source

Reversible UUIDv7-to-v4 facades using the UUIDv47 scheme.

Store a UUIDv7 internally and mask its timestamp when presenting a v4-shaped identifier externally. This is a facade transformation, not a standardized UUID version 47. The timestamp is XORed with the low 48 bits of SipHash-2-4 over the UUID's 74 random bits. Those random bits are preserved.

Masking is deterministic and does not authenticate identifiers. Ordinary v4 values pass facade?/1, and any valid key decodes them to v7-shaped values. Wrong keys and tampering are not detected. Preserved random bits allow correlation with the original UUID and across key changes.

Keep keys secret and stable for the lifetime of issued facades. Store key IDs outside the UUID when rotating keys. Use normal authorization checks for decoded identifiers. See the UUIDv47 guide and the upstream scheme.

Summary

Functions

Checks raw RFC-variant v4 shape, including ordinary v4 UUIDs; does not authenticate.

Generates a UUIDv7 and masks it, returning the requested UUID format.

Generates two unsigned 64-bit key words from a cryptographically secure source.

Masks an RFC-variant UUIDv7 raw binary as a v4-shaped raw binary.

Unmasks an RFC-variant v4 raw binary using the original key.

Checks whether a raw binary is an RFC-variant UUIDv7 that can be masked.

Types

key()

@type key() :: Uniq.SipHash.key()

uuid()

@type uuid() :: <<_::128>>

Functions

facade?(arg1)

@spec facade?(term()) :: boolean()

Checks raw RFC-variant v4 shape, including ordinary v4 UUIDs; does not authenticate.

generate(key, format \\ :default)

@spec generate(key(), Uniq.UUID.format()) :: Uniq.UUID.formatted()

Generates a UUIDv7 and masks it, returning the requested UUID format.

iex> facade = Uniq.UUIDv47.generate(Uniq.UUIDv47.generate_key())
iex> byte_size(facade)
36

generate_key()

@spec generate_key() :: key()

Generates two unsigned 64-bit key words from a cryptographically secure source.

iex> {k0, k1} = Uniq.UUIDv47.generate_key()
iex> k0 in 0..0xFFFFFFFFFFFFFFFF and k1 in 0..0xFFFFFFFFFFFFFFFF
true

mask(arg1, key)

@spec mask(uuid(), key()) :: uuid()

Masks an RFC-variant UUIDv7 raw binary as a v4-shaped raw binary.

The key is a tuple of numeric unsigned 64-bit words {k0, k1}, matching the upstream C API. A standard SipHash byte key maps to little-endian words.

iex> uuid = Uniq.UUID.string_to_binary!("00000000-0000-7000-8000-000000000000")
iex> facade = Uniq.UUIDv47.mask(uuid, {0x0123456789ABCDEF, 0xFEDCBA9876543210})
iex> Uniq.UUID.to_string(facade)
"22d97126-9609-4000-8000-000000000000"

unmask(arg1, key)

@spec unmask(uuid(), key()) :: uuid()

Unmasks an RFC-variant v4 raw binary using the original key.

This checks only the input's shape. Any v4 value and valid key produce a v7-shaped result; success does not establish provenance or validate the key.

iex> uuid = Uniq.UUID.uuid7(:raw)
iex> key = {0x0123456789ABCDEF, 0xFEDCBA9876543210}
iex> Uniq.UUIDv47.unmask(Uniq.UUIDv47.mask(uuid, key), key) == uuid
true

v7?(arg1)

@spec v7?(term()) :: boolean()

Checks whether a raw binary is an RFC-variant UUIDv7 that can be masked.