nuid
View SourceUnique identifier generation for Erlang/OTP 27+: RFC 4122 and RFC 9562 UUIDs, plus sortable nuid identifiers.
Getting started
%% rebar.config
{deps, [nuid]}.1> nuid:uuid4().
<<"37a9e737-f680-44a9-b83d-a517ec758b75">>
2> nuid:uuid7().
<<"018b3d7a-9f9a-7577-adb2-08761e3d87f7">>
3> nuid:nuid2().
<<"OHtpP-----Fkn3F6JaT5Kxnm_NAiDzFgGMzc">>
4> nuid:uuid7_info(nuid:uuid7()).
{{2023,10,17},{11,52,8}}Features
- RFC 4122 UUIDs versions 1, 3 (MD5), 4, and 5 (SHA-1) (RFC 4122)
- RFC 9562 UUIDs versions 6, 7, and 8 (RFC 9562)
- Nil and max UUIDs
nuid1andnuid2sortable identifiers with 128 bits of cryptographically strong randomness- Info recovery creation time and originating node from generated identifiers
- No dependencies only OTP
kernel,stdlib, andcrypto
API
| Function | Description |
|---|---|
nuid:uuid1/0 | RFC 4122 UUID v1 |
nuid:uuid3/2 | RFC 4122 UUID v3 (MD5, name-based) |
nuid:uuid4/0 | RFC 4122 UUID v4 (random) |
nuid:uuid5/2 | RFC 4122 UUID v5 (SHA-1, name-based) |
nuid:uuid6/0 | RFC 9562 UUID v6 (time-ordered) |
nuid:uuid7/0 | RFC 9562 UUID v7 (time-ordered) |
nuid:uuid8/1, nuid:uuid8/3 | RFC 9562 UUID v8 (vendor-specific) |
nuid:nil_uuid/0 | RFC 4122 nil UUID |
nuid:max_uuid/0 | RFC 9562 max UUID |
nuid:nuid1/0 | nuid1 identifier |
nuid:nuid2/0 | nuid2 identifier |
nuid:uuid1_info/1, nuid:uuid6_info/1 | Generation time, node, and counter |
nuid:uuid7_info/1, nuid:nuid1_info/1 | Generation time |
nuid:nuid2_info/1 | Generation time and node |
The nuid identifiers
We have historically used UUID v1 (RFC 4122) and later UUID v6 (RFC 9562), preferring v6 because it can be ordered by creation time.
A later security review required identifiers with at least as many cryptographically strong random bits as UUID v4 (122). The requirements were:
- Orderable by creation time.
- At least 122 bits of cryptographically strong randomness.
With, optionally:
- Uniqueness (or at least a low collision probability).
- Information about where the identifier was created.
The two de facto standards we looked at, ulid
and ksuid, do not meet the randomness
requirement, so we defined nuid2.
nuid2 properties:
- Lexicographically sortable.
- Sixteen cryptographically strong random bytes (128 bits).
- Unique (or at least a low collision probability).
- Carries 3 bytes reserved for origin information.
- No longer than a UUID (36 characters).
- URL-safe.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| POSIX time in seconds |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Unique sortable integer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Origin information (node) | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
| |
+ +
| Cryptographically strong random bits (128) |
+ +
| |
+ +-+-+-+-+-+-+-+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 1: nuid2 field and bit layoutWe encode this in what we call base64': a URL-safe, sortable base64 representation. Its alphabet, in order:
-, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
_,
a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, zIt is the Erlang/OTP base64 module reordered to preserve byte ordering.
nuid1 is a lighter identifier with these properties:
- Lexicographically sortable. It can replace UUID v6: every
nuid1generated after a UUID v6 sorts after it. - Sixteen cryptographically strong random bytes (128 bits).
- Unique (or at least a low collision probability).
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Hex unique time in us |-| base64' 16 random bytes |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 2: nuid1 field and byte layout
(*) the dash at byte 14 is ASCII 45Benchmarks
Run a rebar3 shell using the bench profile:
rebar3 as bench shell
1> nuid_bench:bench().This benchmark compares the different identifiers generated by nuid.
nuid1 creation time: 1.83 (us)
nuid2 creation time: 1.55 (us)
uuid1 creation time: 0.92 (us)
uuid4 creation time: 1.69 (us)
uuid6 creation time: 0.91 (us)
uuid7 creation time: 1.82 (us)Documentation
License
Apache License 2.0