Implementing

Test vectors

From the Rust reference implementation (tnid 0.2.0), cross-checked against an independent implementation written from the spec, which has no vectors. Encryption vectors are the TypeScript library's Rust-compatibility tests. All in test-vectors.json.

Fields: ms decimal; random, payload, key hex; uuid lowercase UUID form; payload is the 100-bit value in bit layout order.

Names

Name20-bit value (hex)
a30000
008000
ab31c00
a1b2308e3
postad319
testcab19
userd6157
zzzzfffff

Variant 0

Inputs: name, milliseconds since the Unix epoch, 57 random bits.

name     a
ms       0
random   0
string   a.-----------------
uuid     30000000-0000-8000-8000-000000000000

name     user
ms       1234567890
random   0
string   user.--Zmk4cF---------
uuid     d6157000-932c-805a-8400-000000000000

name     test
ms       1767502656561
random   123456789abcde
string   test.Br2flcN7HC4OsafnT
uuid     cab19337-0ebc-8686-8212-3456789abcde

name     zzzz
ms       8796093022207
random   1ffffffffffffff
string   zzzz.zzzzzzwzzzzzzzzzz
uuid     ffffffff-ffff-8fff-8fff-ffffffffffff

8796093022207 = 2⁴³ − 1, the largest timestamp.

Timestamp wrap

Timestamps past 2⁴³ − 1 SHOULD wrap: 9999999999999 mod 2⁴³ = 1203906977791.

name     post
ms       9999999999999   (stored as 1203906977791)
random   154a98ceb1f0ad2
string   post.7kbDJzwxJeNnf6kfH
uuid     ad319230-9ce5-83ff-8f54-a98ceb1f0ad2

Variant 1

Inputs: name, 100-bit payload.

name     a
payload  0
string   a.------0----------
uuid     30000000-0000-8000-9000-000000000000

name     b
payload  1
string   b.------0---------0
uuid     38000000-0000-8000-9000-000000000001

name     test
payload  123456789abcdef0123456789
string   test.3YGLT8djCvk3YGLT8
uuid     cab19123-4567-889a-9bcd-ef0123456789

name     zzzz
payload  fffffffffffffffffffffffff
string   zzzz.zzzzzzxzzzzzzzzzz
uuid     ffffffff-ffff-8fff-9fff-ffffffffffff

Round trips

Each pair is one TNID; parsing either side gives the other.

string   test.x8MRU0xetVa6QZeZR
uuid     cab19f49-5dc7-8c1f-9ab9-8261db92a91c
variant  1

string   user.Br2flcNDfF6LYICnT
uuid     d6157337-0ebc-8686-83ab-4075a34cdcde
variant  0

string   user.BsOdOgguzJorJeVH7
uuid     d6157338-6696-86cb-8ebf-534dd4aa0488
variant  0

string   user.Br2flcPDfF6LYICnT
uuid     d6157337-0ebc-8686-a3ab-4075a34cdcde
variant  2 (reserved)

string   user.Br2flcQDfF6LYICnT
uuid     d6157337-0ebc-8686-b3ab-4075a34cdcde
variant  3 (reserved)

Parsers SHOULD accept the reserved variants 2 and 3. UUID input is case-insensitive: D6157337-0EBC-8686-83AB-4075A34CDCDE parses to user.Br2flcNDfF6LYICnT.

Must reject

Required by the spec's MUST rules, and for UUID form by RFC 9562, which the spec defers to.

TNID stringReason
User.Br2flcNDfF6LYICnTUppercase in the name
users.Br2flcNDfF6LYICnTName longer than 4
5.Br2flcNDfF6LYICnT5 not in the name alphabet
.Br2flcNDfF6LYICnTEmpty name
user.Br2flcNDfF6LYICn16 data characters
user.Br2flcNDfF6LYICnTx18 data characters
user.Br2flcNDfF6LYIC+T+ not in the data alphabet
user.Br2flcNDfF6LY.CnTTwo dots; data is 17 characters, but . is not in the data alphabet
user.Empty data
user.Br2flcNDfF6LYICnT with a leading space or trailing newlineWhitespace: reject, don't trim
usér.Br2flcNDfF6LYICnTé not in the name alphabet (4 code points long)
user.Br2flcNDfF6LYICnТLast character is Cyrillic Т (U+0422), not ASCII T
UUIDReason
d6157337-0ebc-8686-83ab-4075a34cdcd31 hex digits
d6157337-0ebc-8686-83ab-4075a34cdcde033 hex digits
d6157337-0ebc-4686-83ab-4075a34cdcdeUUID version 4
d6157337-0ebc-9686-83ab-4075a34cdcdeUUID version 9
d6157337-0ebc-8686-c3ab-4075a34cdcdeUUID variant 0b11
00000000-0000-8000-8000-000000000000All-null name
300e0000-0000-8000-8000-000000000000Name a, null, b, null: character after a null

tnid 0.2.0 checks only the high bit of the version and variant fields, so it accepts the version 9 and variant 0b11 inputs. Check for exact equality.

Left open by the spec

Tests should allow accepting or rejecting them. tnid 0.2.0 rejects all three. A parser that accepts one outputs the lowercase, hyphenated UUID form.

InputForm
d61573370ebc868683ab4075a34cdcdeNo hyphens
{d6157337-0ebc-8686-83ab-4075a34cdcde}Braces
urn:uuid:d6157337-0ebc-8686-83ab-4075a34cdcdeURN prefix

Encryption

V0/V1 encryption: encrypting v0 with key gives v1; decrypting v1 gives v0.

key      00000000000000000000000000000000
v0       a.-----------------
v1       a.qjrH3l_XfqYmAVUgO

key      0102030405060708090a0b0c0d0e0f10
v0       user.--Zmk4cF---------
v1       user.S1PcM9daFtzp1lJM5

key      0102030405060708090a0b0c0d0e0f10
v0       user.BsOdOgguzJorJeVH7
v1       user.-8hAMlKY0mjrmzQHv

key      2b7e151628aed2a6abf7158809cf4f3c
v0       post.7kbDJzwxJeNnf6kfH
v1       post.X3Wxwp0wOy4OZp_rP

Blocklist filtering is non-deterministic and has no vectors: check that generated TNIDs never contain a blocklisted pattern, in any case.