RFC 9562
Universally Unique IDentifiers (UUIDs)
Universally Unique IDentifiers (UUIDs) ๐ฆ
Okay bestie, let's get the paperwork out of the way first ๐โจ This is RFC 9562, a Standards Track doc (ISSN 2070-1721) published in May 2024. Three authors: K. Davis from Cisco Systems, B. Peabody from Uncloud, and P. Leach from the University of Washington. It obsoletes RFC 4122, which means this is the new official version of the UUID spec ๐ It doesn't list any RFC it updates.
Abstract
Okay so, this spec defines UUIDs (Universally Unique IDentifiers), also called GUIDs (Globally Unique IDentifiers), plus a Uniform Resource Name namespace for them ๐ A UUID is 128 bits long and is meant to guarantee uniqueness across space and time, which is honestly iconic. UUIDs started out in the Apollo Network Computing System (NCS), then moved into the Open Software Foundation's (OSF's) Distributed Computing Environment (DCE), and then landed in Microsoft Windows platforms ๐ช
This spec is derived from the OSF DCE spec, used with the kind permission of the OSF (now called "The Open Group") ๐ Info from earlier versions of the OSF DCE spec has been folded in too. And yes, this document obsoletes RFC 4122.
Status of This Memo
This is an Internet Standards Track document ๐
It's a product of the Internet Engineering Task Force (IETF) and represents the consensus of the IETF community ๐ซถ It got public review and was approved for publication by the Internet Engineering Steering Group (IESG). If you want more info on Internet Standards, check Section 2 of RFC 7841 ๐
Info about the current status of this document, any errata, and how to send feedback is at https://www.rfc-editor.org/info/rfc9562 ๐
Copyright Notice
Copyright (c) 2024 IETF Trust and the persons identified as the document authors. All rights reserved ๐
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) as they stand on the date of publication. Please read these carefully, because they explain your rights and restrictions for this document ๐ Code Components pulled out of this document must include Revised BSD License text, as described in Section 4.e of the Trust Legal Provisions, and they come without warranty, as described in the Revised BSD License.
Table of Contents
1. Introduction
2. Motivation
2.1. Update Motivation
3. Terminology
3.1. Requirements Language
3.2. Abbreviations
4. UUID Format
4.1. Variant Field
4.2. Version Field
5. UUID Layouts
5.1. UUID Version 1
5.2. UUID Version 2
5.3. UUID Version 3
5.4. UUID Version 4
5.5. UUID Version 5
5.6. UUID Version 6
5.7. UUID Version 7
5.8. UUID Version 8
5.9. Nil UUID
5.10. Max UUID
6. UUID Best Practices
6.1. Timestamp Considerations
6.2. Monotonicity and Counters
6.3. UUID Generator States
6.4. Distributed UUID Generation
6.5. Name-Based UUID Generation
6.6. Namespace ID Usage and Allocation
6.7. Collision Resistance
6.8. Global and Local Uniqueness
6.9. Unguessability
6.10. UUIDs That Do Not Identify the Host
6.11. Sorting
6.12. Opacity
6.13. DBMS and Database Considerations
7. IANA Considerations
7.1. IANA UUID Subtype Registry and Registration
7.2. IANA UUID Namespace ID Registry and Registration
8. Security Considerations
9. References
9.1. Normative References
9.2. Informative References
Appendix A. Test Vectors
A.1. Example of a UUIDv1 Value
A.2. Example of a UUIDv3 Value
A.3. Example of a UUIDv4 Value
A.4. Example of a UUIDv5 Value
A.5. Example of a UUIDv6 Value
A.6. Example of a UUIDv7 Value
Appendix B. Illustrative Examples
B.1. Example of a UUIDv8 Value (Time-Based)
B.2. Example of a UUIDv8 Value (Name-Based)
Acknowledgements
Authors' Addresses
1. Introduction โจ
This spec defines a Uniform Resource Name namespace for Universally Unique IDentifiers (UUIDs), also known as Globally Unique IDentifiers (GUIDs) ๐ฆ A UUID is 128 bits long and requires no central registration process, so it's basically self-serve.
UUIDs are everywhere in computing, no cap. They're the core identifier infrastructure for lots of operating systems like Microsoft Windows and apps like the Mozilla Web browser. In many cases they end up exposed in all kinds of non-standard ways ๐
This spec tries to standardize that practice as openly as possible, in a way that benefits the whole Internet ๐ธ The goal is to be a concise guide for anyone who wants to build services with UUIDs, whether that's alongside URNs [RFC8141] or on their own.
There's an ITU-T Recommendation and an ISO/IEC Standard [X667] derived from [RFC4122]. Both sets of specs are aligned and fully technically compatible, which is so satisfying ๐ง Nothing in this document should be read as overriding the DCE standards that defined UUIDs.
2. Motivation ๐
One of the main reasons to use UUIDs is that no centralized authority is needed to administer them. (Two formats may use optional IEEE 802 Node IDs, but others don't.) So generation on demand can be totally automated and used for all sorts of purposes ๐ค The generation algorithm described here supports very high allocation rates, 10 million per second per machine or more if needed, so they could even be used as transaction IDs. Main character energy ๐
UUIDs are a fixed size (128 bits), which is reasonably small compared to the alternatives. That makes them great for sorting, ordering, and hashing of all sorts, storing in databases, simple allocation, and just generally easy to program with ๐
Since UUIDs are unique and persistent, they make excellent URNs ๐ Being able to generate a new UUID without a registration process means UUIDs are one of the URNs with the lowest minting cost. Iykyk.
2.1. Update Motivation ๐
So much has changed since UUIDs were first created ๐ญ Modern apps need to create and use UUIDs as the primary identifier for all kinds of things in complex systems, including (but not limited to) database keys, file names, machine or system names, and identifiers for event-driven transactions.
One area where UUIDs have gotten really popular is database keys. That's because modern apps are way more distributed. In those cases, the "auto-increment" schemes databases often use just don't work well, since coordinating sequential numeric IDs across a network can turn into a huge burden. UUIDs can create unique, reasonably short values in distributed systems without any coordination, which makes them a great alternative. But UUID versions 1-5, which were originally defined by [RFC4122], are missing some other desirable traits, like:
- UUID versions that aren't time ordered, such as UUIDv4 (described in Section 5.4), have poor database-index locality. That means new values created in a row aren't close to each other in the index, so inserts have to happen at random locations. The performance hit on the common structures used for this (B-trees and their variants) can be dramatic ๐
- The 100-nanosecond Gregorian Epoch used in UUIDv1 timestamps (described in Section 5.1) is uncommon and hard to represent accurately using a standard number format like the one described in [IEEE754] ๐คฏ
- You need introspection or parsing to order by time sequence, instead of being able to do a simple byte-by-byte comparison.
- Privacy and network security issues come up when a Media Access Control (MAC) address is used in the node field of UUIDv1 ๐ Exposed MAC addresses can be used as an attack surface to locate network interfaces and reveal other info about those machines (at minimum the manufacturer and potentially other details). Plus, with virtual machines and containers, uniqueness of the MAC address is no longer guaranteed.
- Many implementation details specified in [RFC4122] involved trade-offs that aren't possible to specify for all applications, and they aren't necessary to produce interoperable implementations.
- [RFC4122] didn't distinguish between the requirements for generating a UUID and the requirements for simply storing one, even though those are often different ๐ฆ
Because of all the issues above, lots of widely distributed database apps and big app vendors have tried to solve the problem of creating a better time-based, sortable unique identifier for use as a database key. That has led to numerous implementations over the past 10+ years, all solving the same problem in slightly different ways ๐
While preparing this spec, the following 16 different implementations were analyzed for trends in total ID length, bit layout, lexical formatting and encoding, timestamp type, timestamp format, timestamp accuracy, node format and components, collision handling, and multi-timestamp tick generation sequencing ๐
- [ULID]
- [LexicalUUID]
- [Snowflake]
- [Flake]
- [ShardingID]
- [KSUID]
- [Elasticflake]
- [FlakeID]
- [Sonyflake]
- [orderedUuid]
- [COMBGUID]
- [SID]
- [pushID]
- [XID]
- [ObjectID]
- [CUID]
After digging through these implementations and the issues above, this document was written. In it, new UUIDs are adapted to address those issues โจ
[RFC4122] itself also needed an overhaul to cover a bunch of topics, including (but not limited to) the following:
- Implementing miscellaneous errata reports, mostly around bit-layout clarifications that were causing inconsistent implementations [Err1957], [Err3546], [Err4975], [Err4976], [Err5560], etc. ๐ ๏ธ
- Decoupling the other UUID versions from the UUIDv1 bit layout, so fields like "
time_hi_and_version" don't need to be referenced inside a UUID that isn't time based. This also means giving UUIDv3, UUIDv4, and UUIDv5 their own definition sections, similar to the one for UUIDv1 ๐งฉ - Providing implementation best practices for the many real-world scenarios and corner cases seen in existing and prototype implementations ๐ก
- Addressing security best practices and considerations for the modern age as they relate to MAC addresses, hashing algorithms, secure randomness, and other topics ๐
- Giving implementations a standards-based option for implementation-specific and/or experimental UUID designs ๐งช
- Providing more test vectors that illustrate real UUIDs created according to the spec ๐ฆ
3. Terminology ๐
3.1. Requirements Language
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here ๐
3.2. Abbreviations ๐ง
Here's the glossary of every abbreviation this doc uses, so you can keep up:
ABNF: Augmented Backus-Naur FormCSPRNG: Cryptographically Secure Pseudorandom Number GeneratorDBMS: Database Management SystemIEEE: Institute of Electrical and Electronics EngineersITU: International Telecommunication UnionMAC: Media Access ControlMD5: Message Digest 5MSB: Most Significant BitOID: Object IdentifierSHA: Secure Hash AlgorithmSHA-1: Secure Hash Algorithm 1 (with message digest of 160 bits)SHA-3: Secure Hash Algorithm 3 (arbitrary size)SHA-224: Secure Hash Algorithm 2 with message digest size of 224 bitsSHA-256: Secure Hash Algorithm 2 with message digest size of 256 bitsSHA-512: Secure Hash Algorithm 2 with message digest size of 512 bitsSHAKE: Secure Hash Algorithm 3 based on the KECCAK algorithmURN: Uniform Resource NamesUTC: Coordinated Universal TimeUUID: Universally Unique IdentifierUUIDv1: Universally Unique Identifier version 1UUIDv2: Universally Unique Identifier version 2UUIDv3: Universally Unique Identifier version 3UUIDv4: Universally Unique Identifier version 4UUIDv5: Universally Unique Identifier version 5UUIDv6: Universally Unique Identifier version 6UUIDv7: Universally Unique Identifier version 7UUIDv8: Universally Unique Identifier version 8
4. UUID Format โจ
okay so a UUID is 16 octets (128 bits) in size ๐ The variant bits and the version bits (we'll get to those in the next sections) decide the finer structure inside it. For the layout and the numbering, bits count from 0 up to 127 and octets count from 0 up to 15 ๐ฆ
Unless an application or presentation protocol says otherwise, every field gets encoded with the most significant byte first. That's called "network byte order" and it's giving consistency ๐ธ
When you save UUIDs to binary, you sequence all the fields in big-endian format. ngl there's a known caveat here: Microsoft's Component Object Model (COM) GUIDs use little-endian when they're saved. The details are in [MS_COM_GUID], but that discussion is outside the scope of this spec, so we're not going into it here ๐
UUIDs MAY be represented as binary data or as integers. When you're using them with URNs or showing them as text in apps, the go-to format is the "hex-and-dash" string: groups of hexadecimal alphanumerics, uppercase or lowercase, split up by single dashes/hyphens ๐ If you're storing them in databases, check out Section 6.13 โจ
The formal definition of the string representation is written in ABNF [RFC5234]:
UUID = 4hexOctet "-"
2hexOctet "-"
2hexOctet "-"
2hexOctet "-"
6hexOctet
hexOctet = HEXDIG HEXDIG
DIGIT = %x30-39
HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
The alphabetic characters can be all uppercase, all lowercase, or mixed case, per Section 2.3 of [RFC5234]. Here's an example UUID in that textual form ๐
f81d4fae-7dec-11d0-a765-00a0c91e6bf6
Figure 1: Example String UUID Format
The exact same UUID from Figure 1 shows up in binary (Figure 2), as an unsigned integer (Figure 3), and as a URN (Figure 4), which is defined by [RFC8141] ๐ง
111110000001110101001111101011100111110111101100000100011101000\
01010011101100101000000001010000011001001000111100110101111110110
Figure 2: Example Binary UUID
329800735698586629295641978511506172918
Figure 3: Example Unsigned Integer UUID (Shown as a Decimal Number)
urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6
Figure 4: Example URN Namespace for UUID
There are loads of other ways to define a UUID format too! The examples below are not an exhaustive list, and they're only here for informational purposes ๐
- Some UUID implementations, such as those found in [Python] and [Microsoft], output the UUID in string format, dashes included, wrapped in curly braces ๐
- [X667] provides UUID format definitions for using UUIDs with an OID ๐
- [IBM_NCS] is a legacy implementation that produces a unique UUID format compatible with Variant 0xx of Table 1 ๐
4.1. Variant Field ๐ฆ
The variant field decides the layout of the UUID. Basically, how you read every other bit depends on what's set in the variant field. It could more accurately be called a "type" field, but we're keeping the original term for compatibility ๐ The variant field is a variable number of the most significant bits of octet 8 of the UUID.
Table 1 shows what goes in the variant field. The letter "x" means "don't-care" ๐ซถ
+======+======+======+======+=========+=========================+
| MSB0 | MSB1 | MSB2 | MSB3 | Variant | Description |
+======+======+======+======+=========+=========================+
| 0 | x | x | x | 1-7 | Reserved. Network |
| | | | | | Computing System (NCS) |
| | | | | | backward compatibility, |
| | | | | | and includes Nil UUID |
| | | | | | as per Section 5.9. |
+------+------+------+------+---------+-------------------------+
| 1 | 0 | x | x | 8-9,A-B | The variant specified |
| | | | | | in this document. |
+------+------+------+------+---------+-------------------------+
| 1 | 1 | 0 | x | C-D | Reserved. Microsoft |
| | | | | | Corporation backward |
| | | | | | compatibility. |
+------+------+------+------+---------+-------------------------+
| 1 | 1 | 1 | x | E-F | Reserved for future |
| | | | | | definition and includes |
| | | | | | Max UUID as per |
| | | | | | Section 5.10. |
+------+------+------+------+---------+-------------------------+
Table 1: UUID Variants
Interoperability with variants other than the one defined here, in any form, isn't guaranteed. It's not likely to be an issue in practice though ๐ธ
Specifically for UUIDs in this document, bits 64 and 65 of the UUID (bits 0 and 1 of octet 8) MUST be set to 1 and 0 as specified in row 2 of Table 1. That's the main character rule here, so every bit and field layout avoids using these bits ๐
4.2. Version Field โจ
okay so the version number lives in the most significant 4 bits of octet 6, which is bits 48 through 51 of the UUID ๐ฆ
Table 2 is the whole cast of versions for this UUID variant 10xx that this document defines, so let's look at it ๐
+======+======+======+======+=========+============================+
| MSB0 | MSB1 | MSB2 | MSB3 | Version | Description |
+======+======+======+======+=========+============================+
| 0 | 0 | 0 | 0 | 0 | Unused. |
+------+------+------+------+---------+----------------------------+
| 0 | 0 | 0 | 1 | 1 | The Gregorian time-based |
| | | | | | UUID specified in this |
| | | | | | document. |
+------+------+------+------+---------+----------------------------+
| 0 | 0 | 1 | 0 | 2 | Reserved for DCE Security |
| | | | | | version, with embedded |
| | | | | | POSIX UUIDs. |
+------+------+------+------+---------+----------------------------+
| 0 | 0 | 1 | 1 | 3 | The name-based version |
| | | | | | specified in this document |
| | | | | | that uses MD5 hashing. |
+------+------+------+------+---------+----------------------------+
| 0 | 1 | 0 | 0 | 4 | The randomly or |
| | | | | | pseudorandomly generated |
| | | | | | version specified in this |
| | | | | | document. |
+------+------+------+------+---------+----------------------------+
| 0 | 1 | 0 | 1 | 5 | The name-based version |
| | | | | | specified in this document |
| | | | | | that uses SHA-1 hashing. |
+------+------+------+------+---------+----------------------------+
| 0 | 1 | 1 | 0 | 6 | Reordered Gregorian time- |
| | | | | | based UUID specified in |
| | | | | | this document. |
+------+------+------+------+---------+----------------------------+
| 0 | 1 | 1 | 1 | 7 | Unix Epoch time-based UUID |
| | | | | | specified in this |
| | | | | | document. |
+------+------+------+------+---------+----------------------------+
| 1 | 0 | 0 | 0 | 8 | Reserved for custom UUID |
| | | | | | formats specified in this |
| | | | | | document. |
+------+------+------+------+---------+----------------------------+
| 1 | 0 | 0 | 1 | 9 | Reserved for future |
| | | | | | definition. |
+------+------+------+------+---------+----------------------------+
| 1 | 0 | 1 | 0 | 10 | Reserved for future |
| | | | | | definition. |
+------+------+------+------+---------+----------------------------+
| 1 | 0 | 1 | 1 | 11 | Reserved for future |
| | | | | | definition. |
+------+------+------+------+---------+----------------------------+
| 1 | 1 | 0 | 0 | 12 | Reserved for future |
| | | | | | definition. |
+------+------+------+------+---------+----------------------------+
| 1 | 1 | 0 | 1 | 13 | Reserved for future |
| | | | | | definition. |
+------+------+------+------+---------+----------------------------+
| 1 | 1 | 1 | 0 | 14 | Reserved for future |
| | | | | | definition. |
+------+------+------+------+---------+----------------------------+
| 1 | 1 | 1 | 1 | 15 | Reserved for future |
| | | | | | definition. |
+------+------+------+------+---------+----------------------------+
Table 2: UUID Variant 10xx Versions Defined by This Specification
an example version/variant layout for UUIDv4 comes right after the table ๐ here the "M" is where the version goes (0x4, which is 0b0100), and the "N" is where the variant goes. for variant 10xx there are four possible hex values: 0x8 (0b1000), 0x9 (0b1001), 0xA (0b1010), 0xB (0b1011) ๐
00000000-0000-4000-8000-000000000000
00000000-0000-4000-9000-000000000000
00000000-0000-4000-A000-000000000000
00000000-0000-4000-B000-000000000000
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
Figure 5: UUIDv4 Variant Examples
ngl the other UUID variants from Table 1 use different sub-typing or versioning tricks ๐ง the recording and definition of those remaining variant and sub-typing combos are outside the scope of this document, so that's not our problem here ๐
5. UUID Layouts ๐
okay bestie, so to avoid confusion about which bit lives where, inside octets and across versions, the UUID record gets laid out as a grouping of fields in a bit layout with four octets per row ๐ the fields are shown with the most significant one first โจ
5.1. UUID Version 1 โฐ
UUIDv1 is a time-based UUID with a 60-bit timestamp. It's counted in Coordinated Universal Time (UTC) as a count of 100-nanosecond intervals since 00:00:00.00, 15 October 1582, which is the date of the Gregorian reform to the Christian calendar ๐ ๐ธ
UUIDv1 also has a clock sequence field, and it's there to help avoid duplicates that could pop up when the clock gets set backwards in time, or if the Node ID changes ๐
the node field is an IEEE 802 MAC address, usually the host address, or a randomly derived value per Sections 6.9 and 6.10 ๐ซถ
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_low |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_mid | ver | time_high |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| clock_seq | node |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| node |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 6: UUIDv1 Field and Bit Layout
here's the field breakdown, bestie ๐
- time_low: the least significant 32 bits of the 60-bit starting timestamp. It sits in bits 0 through 31 (octets 0-3) ๐ท
- time_mid: the middle 16 bits of the 60-bit starting timestamp. It sits in bits 32 through 47 (octets 4-5) ๐ผ
- ver: the 4-bit version field as defined by Section 4.2, set to 0b0001 (1). It sits in bits 48 through 51 of octet 6 โจ
- time_high: the least significant 12 bits from the 60-bit starting timestamp. It sits in bits 52 through 63 (octets 6-7) ๐ซ
- var: the 2-bit variant field as defined by Section 4.1, set to 0b10. It sits in bits 64 and 65 of octet 8 ๐ฆ
- clock_seq: the 14 bits holding the clock sequence. They sit in bits 66 through 79 (octets 8-9) ๐
- node: a 48-bit spatially unique identifier. It sits in bits 80 through 127 (octets 10-15) ๐
if a system doesn't have UTC but does have local time, it MAY use that instead, as long as it does so consistently throughout the system. it's not recommended though, because generating UTC from local time only needs a time-zone offset, so it's not a big deal to just do it right ๐
if the clock gets set backwards, or might have been set backwards (like if the system was powered off), and the UUID generator can't be sure that no UUIDs were generated with timestamps larger than the value the clock was set to, then the clock sequence MUST be changed ๐ญ if the previous clock sequence value is known, it MAY be incremented. otherwise it SHOULD be set to a random or high-quality pseudorandom value ๐
same vibe if the Node ID changes (like a network card got moved between machines). setting the clock sequence to a random number minimizes the chance of a duplicate caused by small differences in the machines' clock settings ๐ง if the clock sequence tied to the changed Node ID were known, then it MAY be incremented, but that's pretty unlikely ๐
the clock sequence MUST be originally initialized (that is, once in the lifetime of a system) to a random number, so the correlation across systems stays low ๐ฅ this gives maximum protection against Node IDs that move or switch from system to system rapidly ๐โโ๏ธ the initial value MUST NOT be correlated to the Node ID ๐ โโ๏ธ
notes about nodes derived from IEEE 802 (these are important, bestie ๐):
- on systems with multiple IEEE 802 addresses, any available one MAY be used ๐
- on systems with no IEEE address, a randomly or pseudorandomly generated value MUST be used; see Sections 6.9 and 6.10 ๐ธ
- on systems using a 64-bit MAC address, the least significant, rightmost 48 bits MAY be used ๐ฆ
- systems using an IEEE 802.15.4 16-bit address SHOULD instead use their 64-bit MAC address, where the least significant, rightmost 48 bits MAY be used. an alternative is to generate 32 bits of random data and postfix them at the end of the 16-bit MAC address to create a 48-bit value ๐
5.2. UUID Version 2 ๐
UUIDv2 is for DCE Security UUIDs (see [C309] and [C311]) ๐ as such, the definition of these UUIDs is outside the scope of this specification, so we're leaving it to them ๐ซถ
that's the end of this part, bestie, more coming up next ๐โจ
5.3. UUID Version 3 ๐
UUIDv3 is your go-to for making UUIDs from names that live in some namespace and are unique inside it, see Section 6.5 ๐ธ
UUIDv3 values are made by running an MD5 hash [RFC1321] over a Namespace ID value (Section 6.6) glued together with the name you want. Before that happens, both pieces get turned into a canonical sequence of octets, following the standards or conventions of their namespace, in network byte order โจ That MD5 value then fills all 128 bits of the UUID layout, and the version and variant swap in over their bits as defined by Sections 4.2 and 4.1. Appendix A.2 has an example of this bit swap ๐
Want the scoop on picking a name's canonical format? Check Section 6.5 under the heading "A note on names" ๐
Okay, real talk: where possible, UUIDv5 SHOULD be used in lieu of UUIDv3 ๐ซถ For more on MD5 security, see [RFC6151] ๐
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| md5_high |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| md5_high | ver | md5_mid |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| md5_low |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| md5_low |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 7: UUIDv3 Field and Bit Layout ๐ฆ
md5_high: The first 48 bits of the layout are filled with the most significant, leftmost 48 bits from the computed MD5 value. Occupies bits 0 through 47 (octets 0-5).
ver: The 4-bit version field as defined by Section 4.2, set to 0b0011 (3). Occupies bits 48 through 51 of octet 6.
md5_mid: 12 more bits of the layout consisting of the least significant, rightmost 12 bits of 16 bits immediately following md5_high from the computed MD5 value. Occupies bits 52 through 63 (octets 6-7).
var: The 2-bit variant field as defined by Section 4.1, set to 0b10. Occupies bits 64 and 65 of octet 8.
md5_low: The final 62 bits of the layout immediately following the var field to be filled with the least significant, rightmost bits of the final 64 bits from the computed MD5 value. Occupies bits 66 through 127 (octets 8-15)
5.4. UUID Version 4 ๐
UUIDv4 is meant for generating UUIDs from truly random or pseudorandom numbers ๐ฒ
An implementation may generate 128 bits of random data that is used to fill out the UUID fields in Figure 8. The version and variant then replace the respective bits as defined by Sections 4.1 and 4.2 ๐
Alternatively, an implementation MAY choose to randomly generate the exact required number of bits for random_a, random_b, and random_c (122 bits total) and then concatenate the version and variant in the required position ๐ง
For guidelines on random data generation, see Section 6.9 โจ
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random_a |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random_a | ver | random_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| random_c |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random_c |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 8: UUIDv4 Field and Bit Layout ๐ฆ
random_a: The first 48 bits of the layout that can be filled with random data as specified in Section 6.9. Occupies bits 0 through 47 (octets 0-5).
ver: The 4-bit version field as defined by Section 4.2, set to 0b0100 (4). Occupies bits 48 through 51 of octet 6.
random_b: 12 more bits of the layout that can be filled random data as per Section 6.9. Occupies bits 52 through 63 (octets 6-7).
var: The 2-bit variant field as defined by Section 4.1, set to 0b10. Occupies bits 64 and 65 of octet 8.
random_c: The final 62 bits of the layout immediately following the var field to be filled with random data as per Section 6.9. Occupies bits 66 through 127 (octets 8-15).
5.5. UUID Version 5 ๐ฅ
UUIDv5 is meant for generating UUIDs from "names" that are drawn from, and unique within, some "namespace" as per Section 6.5 ๐
UUIDv5 values are created by computing an SHA-1 hash [FIPS180-4] over a given Namespace ID value (Section 6.6) concatenated with the desired name value after both have been converted to a canonical sequence of octets, as defined by the standards or conventions of its namespace, in network byte order. The most significant, leftmost 128 bits of the SHA-1 value are then used to populate all 128 bits of the UUID layout, and the remaining 32 least significant, rightmost bits of SHA-1 output are discarded. The UUID version and variant then replace the respective bits as defined by Sections 4.2 and 4.1. An example of this bit substitution and discarding excess bits can be found in Appendix A.4 ๐ซง
Info on picking a name's canonical format within a namespace lives in Section 6.5 under the heading "A note on names" ๐
There may be scenarios, usually depending on organizational security policies, where SHA-1 libraries may not be available or may be deemed unsafe for use. As such, it may be desirable to generate name-based UUIDs derived from SHA-256 or newer SHA methods. These name-based UUIDs MUST NOT utilize UUIDv5 and MUST be within the UUIDv8 space defined by Section 5.8. An illustrative example of UUIDv8 for SHA-256 name-based UUIDs is provided in Appendix B.2 ๐
For more information on SHA-1 security considerations, see [RFC6194] ๐
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| sha1_high |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| sha1_high | ver | sha1_mid |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| sha1_low |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| sha1_low |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 9: UUIDv5 Field and Bit Layout ๐ฆ
sha1_high: The first 48 bits of the layout are filled with the most significant, leftmost 48 bits from the computed SHA-1 value. Occupies bits 0 through 47 (octets 0-5).
ver: The 4-bit version field as defined by Section 4.2, set to 0b0101 (5). Occupies bits 48 through 51 of octet 6.
sha1_mid: 12 more bits of the layout consisting of the least significant, rightmost 12 bits of 16 bits immediately following sha1_high from the computed SHA-1 value. Occupies bits 52 through 63 (octets 6-7).
var: The 2-bit variant field as defined by Section 4.1, set to 0b10. Occupies bits 64 and 65 of octet 8.
sha1_low: The final 62 bits of the layout immediately following the var field to be filled by skipping the two most significant, leftmost bits of the remaining SHA-1 hash and then using the next 62 most significant, leftmost bits. Any leftover SHA-1 bits are discarded and unused. Occupies bits 66 through 127 (octets 8-15).
5.6. UUID Version 6 ๐
UUIDv6 is a field-compatible version of UUIDv1 (Section 5.1), reordered for improved DB locality, so it plays nicer with databases ๐๏ธ It is expected that UUIDv6 will primarily be implemented in contexts where UUIDv1 is used. Systems that do not involve legacy UUIDv1 SHOULD use UUIDv7 (Section 5.7) instead ๐ท
Instead of splitting the timestamp into the low, mid, and high sections from UUIDv1, UUIDv6 changes this sequence so timestamp bytes are stored from most to least significant. That is, given a 60-bit timestamp value as specified for UUIDv1 in Section 5.1, for UUIDv6 the first 48 most significant bits are stored first, followed by the 4-bit version (same position), followed by the remaining 12 bits of the original 60-bit timestamp โฐ
The clock sequence and node bits remain unchanged from their position in Section 5.1 ๐งฉ
The clock sequence and node bits SHOULD be reset to a pseudorandom value for each new UUIDv6 generated; however, implementations MAY choose to retain the old clock sequence and MAC address behavior from Section 5.1. For more information on MAC address usage within UUIDs, see the Section 8 ๐
The format for the 16-byte, 128-bit UUIDv6 is shown in Figure 10 ๐
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_high |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_mid | ver | time_low |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| clock_seq | node |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| node |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 10: UUIDv6 Field and Bit Layout ๐ฆ
time_high: The most significant 32 bits of the 60-bit starting timestamp. Occupies bits 0 through 31 (octets 0-3).
time_mid: The middle 16 bits of the 60-bit starting timestamp. Occupies bits 32 through 47 (octets 4-5).
ver: The 4-bit version field as defined by Section 4.2, set to 0b0110 (6). Occupies bits 48 through 51 of octet 6.
time_low: 12 bits that will contain the least significant 12 bits from the 60-bit starting timestamp. Occupies bits 52 through 63 (octets 6-7).
var: The 2-bit variant field as defined by Section 4.1, set to 0b10. Occupies bits 64 and 65 of octet 8.
clock_seq: The 14 bits containing the clock sequence. Occupies bits 66 through 79 (octets 8-9).
node: 48-bit spatially unique identifier. Occupies bits 80 through 127 (octets 10-15).
With UUIDv6, the steps for splitting the timestamp into time_high and time_mid are OPTIONAL since the 48 bits of time_high and time_mid will remain in the same order. An extra step of splitting the first 48 bits of the timestamp into the most significant 32 bits and least significant 16 bits proves useful when reusing an existing UUIDv1 implementation ๐ซถ
5.7. UUID Version 7 ๐ฆ
okay so UUIDv7 is giving main character energy ๐ It has a time-ordered value field built from the super well-known Unix Epoch timestamp, aka the number of milliseconds since midnight 1 Jan 1970 UTC, with leap seconds excluded โจ Generally, UUIDv7 has improved entropy characteristics over UUIDv1 (Section 5.1) or UUIDv6 (Section 5.6). no cap, it's a glow-up ๐
UUIDv7 values get made by putting a Unix timestamp in milliseconds into the most significant 48 bits, then filling the remaining 74 bits (the required version and variant bits don't count) with random bits for each new UUIDv7 generated, so they stay unique as per Section 6.9. Alternatively, implementations MAY fill those 74 bits, jointly, with a combo of the following subfields, in this order from the most significant bits to the least, to guarantee additional monotonicity within a millisecond ๐
- An OPTIONAL sub-millisecond timestamp fraction (12 bits at maximum) as per Section 6.2 (Method 3).
- An OPTIONAL carefully seeded counter as per Section 6.2 (Method 1 or 2).
- Random data for each new UUIDv7 generated for any remaining space.
Implementations SHOULD utilize UUIDv7 instead of UUIDv1 and UUIDv6 if possible ๐ธ
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms | ver | rand_a |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| rand_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rand_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 11: UUIDv7 Field and Bit Layout
unix_ts_ms: the 48-bit big-endian unsigned number of the Unix Epoch timestamp in milliseconds as per Section 6.1. It occupies bits 0 through 47 (octets 0-5).
ver: the 4-bit version field as defined by Section 4.2, set to 0b0111 (7). It occupies bits 48 through 51 of octet 6.
rand_a: 12 bits of pseudorandom data to provide uniqueness as per Section 6.9 and/or optional constructs to guarantee additional monotonicity as per Section 6.2. It occupies bits 52 through 63 (octets 6-7).
var: the 2-bit variant field as defined by Section 4.1, set to 0b10. It occupies bits 64 and 65 of octet 8.
rand_b: the final 62 bits of pseudorandom data to provide uniqueness as per Section 6.9 and/or an optional counter to guarantee additional monotonicity as per Section 6.2. It occupies bits 66 through 127 (octets 8-15).
5.8. UUID Version 8 ๐ฅ
UUIDv8 provides a format for experimental or vendor-specific use cases, so it's the "make it your own" option ๐ง The only requirement is that the variant and version bits MUST be set as defined in Sections 4.1 and 4.2. UUIDv8's uniqueness will be implementation specific and MUST NOT be assumed. so don't just assume it's unique, babe ๐
The only explicitly defined bits are those of the version and variant fields, which leaves 122 bits for implementation-specific UUIDs. To be clear, UUIDv8 is not a replacement for UUIDv4 (Section 5.4), where all 122 extra bits are filled with random data ๐
Some example situations where UUIDv8 usage could happen:
- An implementation would like to embed extra information within the UUID other than what is defined in this document.
- An implementation has other application and/or language restrictions that inhibit the use of one of the current UUIDs.
Appendix B provides two illustrative examples of custom UUIDv8 algorithms to address two example scenarios ๐
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| custom_a |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| custom_a | ver | custom_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| custom_c |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| custom_c |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 12: UUIDv8 Field and Bit Layout
custom_a: the first 48 bits of the layout, which can be filled as an implementation sees fit. It occupies bits 0 through 47 (octets 0-5).
ver: the 4-bit version field as defined by Section 4.2, set to 0b1000 (8). It occupies bits 48 through 51 of octet 6.
custom_b: 12 more bits of the layout, which can be filled as an implementation sees fit. It occupies bits 52 through 63 (octets 6-7).
var: the 2-bit variant field as defined by Section 4.1, set to 0b10. It occupies bits 64 and 65 of octet 8.
custom_c: the final 62 bits of the layout, immediately following the var field, to be filled as an implementation sees fit. It occupies bits 66 through 127 (octets 8-15).
5.9. Nil UUID ๐ซง
The Nil UUID is a special form of UUID that is specified to have all 128 bits set to zero. It's the "zero vibes" one ๐
00000000-0000-0000-0000-000000000000
Figure 13: Nil UUID Format
A Nil UUID value can be useful for communicating the absence of any other UUID value in situations that otherwise require or use a 128-bit UUID. A Nil UUID can express the concept "no such value here" โจ Thus, it is reserved for such use as needed for implementation-specific situations.
Note that the Nil UUID value falls within the range of the Apollo NCS variant as per the first row of Table 1 rather than the variant defined by this document. ๐
5.10. Max UUID ๐
The Max UUID is a special form of UUID that is specified to have all 128 bits set to 1. This UUID can be thought of as the inverse of the Nil UUID defined in Section 5.9. Nil's total opposite, iykyk ๐
FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF
Figure 14: Max UUID Format
A Max UUID value can be used as a sentinel value in situations where a 128-bit UUID is required, but a concept such as "end of UUID list" needs to be expressed, and it is reserved for such use as needed for implementation-specific situations ๐ง
Note that the Max UUID value falls within the range of the "yet-to-be defined" future UUID variant as per the last row of Table 1 rather than the variant defined by this document. ๐
6. UUID Best Practices ๐
The minimum requirements for generating UUIDs of each version are described in this document. Everything else is an implementation detail, and it is up to the implementer to decide what is appropriate for a given implementation. Various relevant factors are covered below to help guide an implementer through the different trade-offs among differing UUID implementations ๐
6.1. Timestamp Considerations โฐ
Okay bestie, the timestamp is the part you really have to get right ๐ UUIDv7 was a huge debate while this spec was being made (people were ARGUING ๐ญ), and picking the right timestamp for your app is so important. This section covers the most common points ๐ธ
Reliability: Implementations grab the current timestamp from a reliable source so the values stay time ordered and always go up โจ Watch out for timestamp changes coming from the environment or the OS, and handle them in a way that matches the implementation requirements. Like, if the system clock can move backward (manual adjustment, or a time sync protocol correcting it), implementations need to figure out what they're gonna do in that case ๐ (See "Altering, Fuzzing, or Smearing" below.)
Source: UUIDv1 and UUIDv6 both use a Gregorian Epoch timestamp, while UUIDv7 goes with a Unix Epoch timestamp ๐ฐ๏ธ If you need some other timestamp source or a custom Epoch, UUIDv8 MUST be used ๐
Sub-second Precision and Accuracy: There are sooo many precision levels: milliseconds, microseconds, nanoseconds, and beyond ๐คฏ You might also want fractional sub-second values so you can mix precisions in a time-ordered way. Also, system clocks have their own underlying granularity, which is often coarser than what the OS offers ๐
With UUIDv1 and UUIDv6 you get 100 nanoseconds of precision ๐ฅ, while UUIDv7 has millisecond precision by default in the Unix Epoch. That doesn't go past what most modern systems can actually handle โจ For other precision levels, UUIDv8 has your back ๐ฆ
Kinda like Section 6.2: with UUIDv1 or UUIDv6, you can simulate a high-resolution timestamp by keeping a count of how many UUIDs were generated with the same system time value, then using that count to fill the low order bits of the timestamp ๐ง The high-resolution count goes from zero up to the number of 100-nanosecond intervals per system-time interval.
Length: The length of the timestamp decides how many ticks fit in a UUID before the timestamp field hits its max value, so pick the right length for your timestamp ๐ UUIDv1 and UUIDv6 use a 60-bit timestamp that's good until 5623 AD (that's a long time away, bestie ๐ญ). UUIDv7 has a 48-bit timestamp valid until the year 10889 AD ๐
Altering, Fuzzing, or Smearing: Implementations MAY alter the actual timestamp ๐ Examples include security considerations around putting a real-clock value into a UUID to 1) correct inaccurate clocks, 2) handle leap seconds, or 3) get a millisecond value by dividing by 1024 (or some other number) for performance reasons, instead of dividing microseconds by 1000 โก This spec makes no requirement or guarantee about how close the clock value has to be to the actual time ๐คทโโ๏ธ If UUIDs don't need to be generated super often, the UUIDv1 or UUIDv6 timestamp can just be the system time multiplied by the number of 100-nanosecond intervals per system-time interval ๐
Padding: When you need timestamp padding, implementations MUST pad the most significant bits (leftmost) with data ๐ซถ For example, fill the most significant, leftmost bits of a Unix timestamp with zeroes to finish the 48-bit timestamp in UUIDv7. Another option is filling the most significant, leftmost bits with the number of 32-bit Unix timestamp rollovers after 2038-01-19 ๐ธ
Truncating: When timestamps need truncating, the lower, least significant bits MUST be used โ๏ธ For example, truncating a 64-bit Unix timestamp down to the least significant, rightmost 48 bits for UUIDv7 ๐
Error Handling: If a system overruns the generator by requesting too many UUIDs within a single system-time interval, the UUID service can return an error or stall the UUID generator until the system clock catches up. It MUST NOT knowingly return duplicate values due to a counter rollover ๐จ Note that if processors overrun UUID generation frequently, additional Node IDs can be allocated to the system. That permits higher speed allocation by making multiple UUIDs potentially available for each timestamp value ๐ Similar techniques are discussed in Section 6.4 โจ
6.2. Monotonicity and Counters ๐ฆ
okay so monotonicity (each new value being greater than the last one) is literally the backbone of time-based sortable UUIDs ๐ normally, time-based UUIDs from this document will be monotonic because of the embedded timestamp โจ but implementations can guarantee extra monotonicity with the stuff in this section ๐ซถ
take care to make sure UUIDs generated in batches are also monotonic ๐ like, if one thousand UUIDs get made for the same timestamp, there should be enough logic to keep track of the creation order of those one thousand UUIDs ๐ญ batch UUID creation implementations MAY use a monotonic counter that goes up for each UUID created during a given timestamp ๐ธ
for single-node UUID implementations that don't need to make batches, the embedded timestamp in UUIDv6 and UUIDv7 can give you enough monotonicity just by making sure the timestamp goes up before you make a new UUID ๐ง distributed nodes get covered in Section 6.4 ๐
implementations SHOULD use the following methods for single-node UUID implementations that need batch UUID creation or are otherwise worried about monotonicity with high-frequency UUID generation ๐
Fixed Bit-Length Dedicated Counter (Method 1) ๐ okay so some implementations set aside a specific number of bits in the UUID layout for the sole job of counting how many UUIDs got created during a given UUID timestamp tick ๐ if it's there, a fixed bit-length counter MUST be positioned immediately after the embedded timestamp ๐ this helps with sortability and lets random data get generated for each counter increment โจ with this method, the rand_a section (or a subset of its leftmost bits) of UUIDv7 gets used as a fixed bit-length dedicated counter that goes up for every UUID generation ๐ฆ the trailing random bits generated for each new UUID in rand_b can help make the UUIDs unguessable ๐ if more counter bits are needed, the most significant (leftmost) bits of rand_b MAY be used as extra counter bits ๐
Monotonic Random (Method 2) ๐ธ with this method, the random data also works as a counter ๐ซถ this monotonic value can be thought of as a "randomly seeded counter" that MUST be incremented in the least significant position for each UUID created on a given timestamp tick ๐ฅ UUIDv7's rand_b section SHOULD be used with this method to handle batch UUID generation during a single timestamp tick ๐ the increment value for every UUID generation is a random integer of any desired length larger than zero ๐ that keeps the UUIDs at the level of unguessability the underlying entropy gives them โจ the increment value MAY be 1 when how many UUIDs get generated in a given period of time matters and guessability isn't an issue ๐ but incrementing the counter by 1 SHOULD NOT be used by implementations that favor unguessability, because those values are super easy to guess ๐ญ
Replace Leftmost Random Bits with Increased Clock Precision (Method 3) ๐ง for UUIDv7, which has millisecond timestamp precision, it's possible to use the extra clock precision the system has to stand in for up to 12 random bits right after the timestamp ๐ this can give you values that are time ordered with sub-millisecond precision, using however many bits fit the implementation environment ๐ with this method, the additional time precision bits MUST follow the timestamp as the next available bit in the rand_a field for UUIDv7 ๐ฆ
okay so to calculate this value, start with the portion of the timestamp expressed as a fraction of the clock's tick value (a fraction of a millisecond for UUIDv7) โจ then count how many possible values fit in the available bit space, which is 4096 for the UUIDv7 rand_a field ๐ using floating point or scaled integer arithmetic, multiply that fraction of a millisecond by 4096 and round down (toward zero) to an integer ๐ซถ that gives you a number between 0 and the max allowed for the bits you picked, and it sorts monotonically based on time ๐ each increasing fractional value gives you an increasing bit field value, up to the precision those bits can hold ๐
for example, let's say the system timestamp is 1 Jan 2023 12:34:56.1234567 ๐ taking the precision past 1 ms gives you 0.4567 as a fraction of a millisecond ๐ if we want to encode this in 12 bits, we take the count of possible values that fit in those bits (4096, or 2^12), multiply it by our millisecond fraction of 0.4567, and truncate the result to an integer, which gives 1870 ๐ in hexadecimal that's 0x74E, or the binary bits 0b011101001110 ๐ you can then use those 12 bits as the most significant (leftmost) part of the random section of the UUID (like the rand_a field in UUIDv7) ๐ฆ this works for any bit length that fits in a UUID, and applications can pick the right length based on how much clock precision they have ๐ธ but for UUIDv7 it's capped at 12 bits max so there's still enough room for random bits ๐
the main benefit of encoding extra timestamp precision is that it uses time precision the system clock already has to give you values that are more likely to be unique ๐ง so it can simplify some implementations โจ this technique can also be used alongside one of the other methods, where this extra time precision would come right after the timestamp ๐ซถ then, if any bits are going to be used as a clock sequence, they'd follow next ๐
the following sub-topics cover issues that are only about making reliable fixed bit-length dedicated counters ๐
Fixed Bit-Length Dedicated Counter Seeding ๐ implementations using the fixed bit-length counter method randomly initialize the counter with each new timestamp tick ๐ but when the timestamp hasn't gone up, the counter gets incremented by the desired increment logic instead ๐ when you use a randomly seeded counter alongside Method 1, the random value MAY be regenerated with each counter increment without messing up sortability ๐ the downside is that Method 1 is prone to overflows if you don't pick a counter of adequate length, or if the random data leaves little room for the number of increments you need ๐ญ implementations using the fixed bit-length counter method MAY also choose to randomly initialize just a portion of the counter instead of the whole thing ๐ for example, a 24-bit counter could have its 23 least significant, rightmost bits randomly initialized ๐ the remaining most significant, leftmost counter bit is initialized as zero, purely to guard against counter rollovers ๐ฆ
Fixed Bit-Length Dedicated Counter Length ๐ง pick a counter bit-length that can properly handle the level of timestamp precision you're using ๐ธ for example, millisecond precision generally needs a bigger counter than a timestamp with nanosecond precision ๐ general guidance is that the counter SHOULD be at least 12 bits but no longer than 42 bits ๐ be careful that the counter length you pick leaves enough entropy in the random portion of the UUID after the counter โจ that entropy helps keep the UUIDs made within the batch unguessable ๐ซถ
the following sub-topics cover rollover handling with either type of counter method ๐
Counter Rollover Guards ๐ the technique from "Fixed Bit-Length Dedicated Counter Seeding" above, which describes setting aside a segment of the fixed bit-length counter as a rollover guard, also helps mitigate counter rollover issues ๐ฆ the same technique works with monotonic random counter methods by making sure the total length of a possible increment in the least significant, rightmost position is less than the total length of the random value being incremented ๐ that way the most significant, leftmost bits can get incremented as a rollover guard ๐
Counter Rollover Handling ๐ญ counter rollovers MUST be handled by the application to avoid sorting issues ๐ the general guidance is that applications that care about absolute monotonicity and sortability should freeze the counter and wait for the timestamp to move forward, which makes sure monotonicity doesn't break ๐ alternatively, implementations MAY increment the timestamp ahead of the actual time and reinitialize the counter ๐ฆ
implementations MAY use the following logic to make sure UUIDs with embedded counters are monotonic in nature ๐ง
- compare the current timestamp against the previously stored timestamp ๐ธ
- if the current timestamp is equal to the previous timestamp, increment the counter according to the desired method ๐
- if the current timestamp is greater than the previous timestamp, reinitialize the desired counter method for the new timestamp and generate new random bytes (if the bytes were frozen or being used as the seed for a monotonic counter) ๐
Monotonic Error Checking ๐ implementations SHOULD check if the UUID just generated is greater than the previously generated UUID ๐ if that's not the case, a bunch of things could have happened, like clock rollbacks, leap second handling, and counter rollovers ๐ applications SHOULD have enough logic to catch these scenarios and fix the problem so the next UUID generated is greater than the previous one, or they should at least report an appropriate error ๐ to handle this, the general guidance is that the application MAY reuse the previous timestamp and increment the previous counter method ๐ญโจ
6.3. UUID Generator States โจ
Okay so the generator state is optional ๐ซถ and it only has to be read from stable storage once, at boot time, if you load it into a system-wide shared volatile store (and update that copy whenever the stable store changes) ๐พโจ
This stable storage MAY be used to record different bits of the UUID generation, which are super handy for batch UUID generation and for monotonic error checking with UUIDv6 and UUIDv7 ๐ฅ The stored values include, but aren't limited to, the last known timestamp, the clock sequence, counters, and random data ๐
If an implementation has no stable store available, then it MAY proceed with UUID generation as if this were the first UUID created within a batch. ngl this is the least desirable setup ๐ญ because it makes the clock sequence, counters, or random data get created way more often, and that raises the chance of duplicates. Frequent random number generation also puts more stress on the entropy source and/or entropy pool that the random numbers come from ๐
An implementation MAY also return an application error when collision resistance is the utmost concern ๐ซฃ What that error means is up to the application and implementation. Check out Section 6.7 for more on weighting collision tolerance in applications ๐ง
For UUIDv1 and UUIDv6, if the Node ID can never change (like when the network interface card the Node ID comes from is inseparable from the system), or if any change also re-initializes the clock sequence to a random value, then the current Node ID may be returned instead of keeping anything in stable store ๐ธ
Also for UUIDv1 and UUIDv6, the state doesn't have to be written to stable store every single time a UUID is made ๐ The timestamp in the stable store can be set periodically to a value larger than any timestamp used so far. As long as the generated UUIDs have timestamps below that value, and the clock sequence and Node ID stay the same, only the shared volatile copy needs updating ๐ And if the timestamp in stable store is in the future by less than the usual time it takes the system to reboot, a crash won't force the clock sequence to get re-initialized. It's giving resilience ๐
If it's too expensive to access shared state every time a UUID is generated, the system-wide generator can allocate a block of timestamps each time it's called. A per-process generator can then allocate from that block until it runs out ๐ฆ
6.4. Distributed UUID Generation
Some implementations MAY desire multi-node, clustered applications, where two or more nodes independently generate UUIDs that get stored in a common location ๐ UUIDs already have enough entropy that collisions are unlikely, but as the number of UUID generating nodes goes up, so does the chance of a collision ๐ฌ
This section is going to walk through the two extra collision resistance approaches that multi-node UUID implementations in distributed environments have been seen using ๐
Quick heads-up: even though this section covers two methods "for the sake of completeness," implementations should use the pseudorandom Node ID option if extra collision resistance for distributed UUID generation is a requirement ๐ซถ Also, using either method isn't required to do UUID generation in distributed environments, so don't stress ๐ธ
Node IDs: With this method, a pseudorandom Node ID value gets placed inside the UUID layout โจ That identifier helps make sure the bit space for a given node is unique, so the UUIDs won't clash with any UUID made by another node that has a different node id ๐ง Implementations that choose to use an embedded node id SHOULD use UUIDv8 ๐ The node id SHOULD NOT be an IEEE 802 MAC address, per Section 8 ๐ โโ๏ธ Where the node id goes and how many bits it is are up to implementations and are outside the scope of this spec. Creating and negotiating unique node ids among nodes is also out of scope for this specification ๐
Centralized Registry: With this method, every node that creates UUIDs checks a central registry and confirms the generated value is unique ๐ But as apps scale up, talking to that central registry can turn into a bottleneck and hurt UUID generation ๐ฉ Shared knowledge schemes with central or global registries are outside the scope of this specification and are NOT RECOMMENDED ๐ โโ๏ธ
Distributed applications generating UUIDs at a variety of hosts MUST be willing to rely on the random number source at all hosts ๐ฅ No backing out of that one, bestie ๐
6.5. Name-Based UUID Generation
Some people like to call UUIDs made with hashing algorithms (MD5 or SHA-1) "hash-based," but this document keeps the term "name-based" so it stays consistent with earlier published documents and existing implementations ๐ Consistency is everything ๐
The requirements for name-based UUIDs are:
- UUIDs generated at different times from the same name (using the same canonical format) in the same namespace MUST be equal. ๐ซถ
- UUIDs generated from two different names (same or differing canonical format) in the same namespace should be different (with very high probability). โจ
- UUIDs generated from the same name (same or differing canonical format) in two different namespaces should be different (with very high probability). ๐ฆ
- If two UUIDs that were generated from names (using the same canonical format) are equal, then they were generated from the same name in the same namespace (with very high probability). ๐
A note on names:
The idea of a "name" (and "namespace") should be broadly construed and not limited to text ๐ A canonical sequence of octets is one that follows the specification for that name form's canonical representation. A name can take many common forms, but only one of them can be canonical ๐ง If you're implementing new namespaces for UUIDs, you need to check the specification for the canonical form of names in that space, or define a canonical form for the namespace if it doesn't have one yet ๐
Here's the tea ๐ต At the time of writing, the Domain Name System (DNS) [RFC9499] has three conveyance formats: common (www.example.com), presentation (www.example.com.), and wire format (3www7example3com0). Looking at [X500] Distinguished Names (DNs), [RFC4122] allowed either text-based or binary DER-based names as inputs. For Uniform Resource Locators (URLs) [RFC1738], you could give a Fully Qualified Domain Name (FQDN) with or without the protocol identifier, like www.example.com or https://www.example.com. When it comes to Object Identifiers (OIDs) [X660], you could pick dot notation without the leading dot (2.999), dot notation with the leading dot (.2.999), or one of the many formats from [X680], like OID Internationalized Resource Identifier (OID-IRI) (/Joint-ISO-ITU-T/Example) ๐คฏ
Most users will probably default to the common format for DNS, the FQDN format for a URL, the text format for X.500, and dot notation without a leading dot for OID. Even so, name-based UUID implementations generally SHOULD allow arbitrary input that computes name-based UUIDs for any of the example names above, and for others not defined here ๐ Each name format within a namespace will output different UUIDs, so the mechanisms or conventions used for allocating names and making sure they're unique within their namespaces are beyond the scope of this specification ๐
6.6. Namespace ID Usage and Allocation
This section covers the namespace IDs for some potentially interesting namespaces, like DNS [RFC9499], URLs [RFC1738], OIDs [X660], and DNs [X500] ๐ธ
It also covers allocation, IANA registration, and other details that matter for Namespace IDs ๐
+=========+====================================+=========+==========+
|Namespace|Namespace ID Value |Name |Namespace |
| | |Reference|ID |
| | | |Reference |
+=========+====================================+=========+==========+
|DNS |6ba7b810-9dad-11d1-80b4-00c04fd430c8|[RFC9499]|[RFC4122],|
| | | |RFC 9562 |
+---------+------------------------------------+---------+----------+
|URL |6ba7b811-9dad-11d1-80b4-00c04fd430c8|[RFC1738]|[RFC4122],|
| | | |RFC 9562 |
+---------+------------------------------------+---------+----------+
|OID |6ba7b812-9dad-11d1-80b4-00c04fd430c8|[X660] |[RFC4122],|
| | | |RFC 9562 |
+---------+------------------------------------+---------+----------+
|X500 |6ba7b814-9dad-11d1-80b4-00c04fd430c8|[X500] |[RFC4122],|
| | | |RFC 9562 |
+---------+------------------------------------+---------+----------+
Table 3: Namespace IDs
Items can be added to this registry using the Specification Required policy, as per [RFC8126] ๐
For designated experts, Namespace IDs are generally allocated like this ๐งโ๐ป
- The first Namespace ID value, for DNS, was calculated from a time-based UUIDv1 and
6ba7b810-9dad-11d1-80b4-00c04fd430c8, used as a starting point. - Subsequent Namespace ID values increment the least significant, rightmost bit of time_low
6ba7b810while freezing the rest of the UUID to9dad-11d1-80b4-00c04fd430c8. - New Namespace ID values MUST use this same logic and MUST NOT use a previously used Namespace ID value. ๐ซ
- Thus,
6ba7b815is the next available time_low for a new Namespace ID value, with the full ID being6ba7b815-9dad-11d1-80b4-00c04fd430c8. ๐ฆ - The upper bound for time_low in this special use, Namespace ID values, is
fffffffforffffffff-9dad-11d1-80b4-00c04fd430c8, which should be plenty of room for future Namespace ID values ๐
Heads up, bestie: the Namespace ID value 6ba7b813-9dad-11d1-80b4-00c04fd430c8 and its usage are not defined by this document or by [RFC4122]. So it SHOULD NOT be used as a Namespace ID value. ๐
โโ๏ธ
New Namespace ID values MUST be documented as per Section 7 if they're going to be globally available and fully interoperable ๐ Implementations MAY keep using vendor-specific, application-specific, and deployment-specific Namespace ID values, but just know that interoperability isn't guaranteed ๐ซฃ These custom Namespace ID values MUST NOT use the logic above. Instead, generating a UUIDv4 or UUIDv7 Namespace ID value is RECOMMENDED ๐ If collision probability (Section 6.7) and uniqueness (Section 6.8) of the final name-based UUID aren't a problem, an implementation MAY also use UUIDv8 instead to create a custom, application-specific Namespace ID value โจ
Implementations SHOULD provide the ability to input a custom namespace, so they can account for newly registered IANA Namespace ID values outside of the ones listed in this section, or for custom, application-specific Namespace ID values ๐
6.7. Collision Resistance ๐
Okay so bestie, let's talk about collisions ๐ญ Implementations should weigh what happens if two UUIDs end up the same inside their app, and that matters a LOT when they're deciding between UUID versions that lean on randomness (entropy) ๐ฒ versus the other bits, like the ones covered in Sections 6.1 and 6.2 โจ. This is extra important for distributed node collision resistance, which is defined in Section 6.4 ๐ซถ.
There are two example scenarios below to show how serious a collision can be depending on the app ๐ฅ.
Low Impact: A UUID collision made a duplicate log entry, and now the statistics built from that data are a little off ๐. Implementations that aren't hurt by collisions can keep going with the entropy and uniqueness that UUIDs from this document provide ๐ธ.
High Impact: A duplicate key sends an airplane the wrong course, and now people's lives are at risk ๐ฑ๐. In this scenario there is NO margin for error. Collisions must be avoided: failure is unacceptable. Apps handling this kind of thing must use as much collision resistance as they possibly can within their context ๐.
6.8. Global and Local Uniqueness ๐
UUIDs made by this specification MAY be used to give local uniqueness guarantees ๐ . For example, making sure UUIDs created within a local app are unique inside a database MAY be enough for some implementations ๐, especially when global uniqueness outside that app, in other apps, or around the world isn't needed ๐ง.
Okay, real talk: true global uniqueness is impossible to guarantee without a shared knowledge scheme ๐คฏ. But a UUID doesn't REQUIRE a shared knowledge scheme to be unique for practical implementation purposes โจ. Implementations MAY use a shared knowledge scheme, introduced in Section 6.4, however they see fit to extend the uniqueness this specification guarantees ๐ฆ.
6.9. Unguessability ๐
Implementations SHOULD use a cryptographically secure pseudorandom number generator (CSPRNG) ๐ to produce values that are both hard to predict ("unguessable") and unlikely to collide ("unique") ๐. The exception is when a suitable CSPRNG isn't available in the execution environment ๐. Be careful to reseed the CSPRNG state properly whenever the state changes, like on process forks ๐ด, so it keeps working correctly ๐ . The CSPRNG covers the best of Sections 6.7 and 8 in modern UUIDs ๐.
If you want more advice on generating cryptographic-quality random numbers, check out [RFC4086], [RFC8937], and [RANDOM] ๐๐.
6.10. UUIDs That Do Not Identify the Host ๐งโโ๏ธ
This section explains how to generate a UUIDv1 or UUIDv6 value when an IEEE 802 address isn't available or isn't wanted ๐.
Implementations MAY use MAC address randomization techniques [IEEE802.11bh] as an alternative to the pseudorandom logic in this section ๐ฆ.
Or, implementations MAY choose to get a 48-bit cryptographic-quality random number, as per Section 6.9, and use it as the Node ID ๐ฒ. After generating the fully randomized 48-bit node value, implementations MUST set the least significant bit of the first octet of the Node ID to 1 โก. This bit is the unicast or multicast bit, and it is never set in IEEE 802 addresses from network cards ๐. So a UUID from a machine with a network card can NEVER conflict with one from a machine without one ๐. There's an example of generating a randomized 48-bit node value and the bit modification in Appendix A ๐. For more on IEEE 802 addresses and the unicast or multicast and local/global bits, check out [RFC9542] ๐ธ.
Quick note for compatibility with earlier specs: this document uses the unicast or multicast bit instead of the arguably more correct local/global bit ๐ค. That's because MAC addresses with the local/global bit set or not set are BOTH possible on a network, but the unicast or multicast bit doesn't have that problem ๐ . One node can't have a MAC address that multicasts to multiple nodes ๐ซถ.
Also, things like the computer's name and the operating system's name aren't strictly random, but they help tell results apart from the ones other systems make ๐.
How you build a Node ID from this data is system specific โจ, since both the data available and the functions to get it are super system specific ๐ป. But a generic approach is to pile as many sources as you can into a buffer, run it through a message digest (like SHA-256 or SHA-512 from [FIPS180-4]) ๐ฅ, take an arbitrary 6 bytes from the hash value, and set the multicast bit like we talked about above ๐.
6.11. Sorting ๐
UUIDv6 and UUIDv7 are designed so that anything that needs sorting (like database indexes) can sort them as opaque raw bytes ๐, without parsing or introspection ๐.
Time-ordered monotonic UUIDs get better database-index locality because new values sit near each other in the index ๐ฆ. So objects cluster together more easily, which means better performance ๐. In the real world, the difference between this index locality and random data inserts can be one order of magnitude or more ๐ฑ๐ฅ.
UUID formats from this specification are meant to be lexicographically sortable in their textual representation ๐โจ.
UUIDs made by this specification are crafted with big-endian byte order (network byte order) in mind ๐. If you need little-endian style, UUIDv8 is there for custom UUID formats ๐.
6.12. Opacity ๐ซฅ
As general advice, avoiding parsing UUID values unnecessarily is RECOMMENDED ๐ . Instead, treat UUIDs as opaquely as possible ๐. Sure, application-specific stuff could require some introspection (like examining Sections 4.1 or 4.2, or maybe the timestamp of a UUID) โฐ, but the advice here is to skip that or any other parsing unless it's absolutely necessary ๐. Apps tend to be simpler, more interoperable, and faster when you follow this advice ๐๐.
6.13. DBMS and Database Considerations ๐๏ธ
For a lot of apps, like databases, storing UUIDs as text is unnecessarily verbose ๐ฉ. It takes 288 bits to represent a 128-bit UUID value as text! So where it's feasible, UUIDs SHOULD be stored in database apps as the underlying 128-bit binary value ๐.
For other systems, UUIDs MAY be stored in binary form or as text, whatever fits best ๐. Here are the trade-offs:
- Storing in binary form takes up less space and may result in faster data access ๐๏ธ.
- Storing as text takes up more space, but may need less translation if the text form is used after retrieval, which may make it simpler to implement ๐.
DBMS vendors are ENCOURAGED to provide functionality to generate and store UUID formats from this specification ๐. That's for use as identifiers or left parts of identifiers, like (but not limited to) primary keys ๐, surrogate keys for temporal databases โณ, foreign keys in polymorphic relationships ๐, and keys for key-value pairs in JSON columns and key-value databases ๐งฉ. Apps using a monolithic database may find that database-generated UUIDs (instead of client-generated ones) give the BEST UUID monotonicity ๐. On top of UUIDs, additional identifiers MAY be used to ensure integrity and feedback ๐ก๏ธ.
Designers of database schemas are cautioned AGAINST using name-based UUIDs (see Sections 5.3 and 5.5) as primary keys in tables ๐ซ๐ฌ. A super common mistake is assuming a particular value will never change, and then it totally does ๐ญ. Postal codes, license numbers, and other identification numbers seem unique and unchanging at a given point in time, and then later they hit edge cases where they NEED to change ๐. When that identifier changes, and it was used as the "name" input for a name-based UUID, it can break a database structure ๐. In those situations, using any non-name-based UUID version would have put the field somewhere easier to adapt to those changes (primary key excluded from this statement) ๐งธ. So the general advice is to avoid name-based UUID natural keys and use time-based UUID surrogate keys instead, for the problems described in this section ๐.
7. IANA Considerations ๐ธ
All references to [RFC4122] in IANA registries (outside the ones created by this document) have been replaced with references to this document โจ, including the IANA URN namespace registration [URNNamespaces] for UUID ๐. References to Section 4.1.2 of [RFC4122] have been updated to refer to Section 4 of this document ๐.
Finally, IANA should track UUID Subtypes and Special Case "Namespace IDs Values" as specified in Sections 7.1 and 7.2 at this location: <https://www.iana.org/assignments/uuid> ๐๐.
When evaluating requests, the designated expert should consider community feedback ๐ฃ๏ธ, how well-defined the reference specification is ๐, and this specification's requirements ๐. Vendor-specific, application-specific, and deployment-specific values CANNOT be registered ๐ซ. Specification documents should be published in a stable, freely available manner (ideally with a URL) ๐, but they don't need to be standards ๐ . The designated expert will either approve or deny the registration request and tell IANA the decision ๐. Denials should include an explanation and, if it applies, suggestions for how to make the request work ๐ซถ๐ฆ.
7.1. IANA UUID Subtype Registry and Registration ๐
okay so this section sets up a registry called "UUID Subtypes" for the common, widely used UUID standards ๐ฆ here's the whole table, bestie:
+======================+====+=========+================+============+
| Name | ID | Subtype | Variant | Reference |
+======================+====+=========+================+============+
| Gregorian Time-based | 1 | version | OSF DCE | [RFC4122], |
| | | | / IETF | RFC 9562 |
+----------------------+----+---------+----------------+------------+
| DCE Security | 2 | version | OSF DCE | [C309], |
| | | | / IETF | [C311] |
+----------------------+----+---------+----------------+------------+
| MD5 Name-based | 3 | version | OSF DCE | [RFC4122], |
| | | | / IETF | RFC 9562 |
+----------------------+----+---------+----------------+------------+
| Random | 4 | version | OSF DCE | [RFC4122], |
| | | | / IETF | RFC 9562 |
+----------------------+----+---------+----------------+------------+
| SHA-1 Name-based | 5 | version | OSF DCE | [RFC4122], |
| | | | / IETF | RFC 9562 |
+----------------------+----+---------+----------------+------------+
| Reordered Gregorian | 6 | version | OSF DCE | RFC 9562 |
| Time-based | | | / IETF | |
+----------------------+----+---------+----------------+------------+
| Unix Time-based | 7 | version | OSF DCE | RFC 9562 |
| | | | / IETF | |
+----------------------+----+---------+----------------+------------+
| Custom | 8 | version | OSF DCE | RFC 9562 |
| | | | / IETF | |
+----------------------+----+---------+----------------+------------+
Table 4: IANA UUID Subtypes
This table may be extended by Standards Action as per [RFC8126] ๐
For designated experts, there are a few extra things to know โจ
- The minimum and maximum "ID" value for the subtype "version" within the "OSF DCE / IETF" variant is 0 through 15. The versions within Table 1 described as "Reserved for future definition" or "unused" are left out of this IANA registry until they're properly defined ๐
- The "Subtype" column is free-form text. But at publication time, "version" and "family" are the only known UUID subtypes. The "family" subtype lives in the "Apollo NCS" variant space (both are outside the scope of this specification). The Microsoft variant may have subtyping mechanisms defined, but they're unknown and outside this specification's scope. Same deal with the final "Reserved for future definition" variant, which may bring new subtyping logic later on. Subtype IDs are permitted to overlap, so an ID of "1" can show up in multiple variant spaces ๐ฅ
- The "Variant" column is also free-form text. It's likely that one of four values will show up: the first three are "OSF DCE / IETF", "Apollo NCS", and "Microsoft", and the final variant value belongs to the "Reserved for future definition" variant and may bring a new name in the future ๐
7.2. IANA UUID Namespace ID Registry and Registration โจ
this specification defines the "UUID Namespace IDs" registry for common, widely used Namespace ID values ๐
the full details of this registration, including the info for designated experts, are in Section 6.6 ๐
8. Security Considerations ๐
okay bestie, this part is serious, so let's go ๐ซถ
Implementations SHOULD NOT assume that UUIDs are hard to guess ๐ญ For example, they MUST NOT be used as security capabilities (identifiers whose mere possession grants access). If a random number source turns out to be predictable, that's a vulnerability ๐
Implementations MUST NOT assume it's easy to tell whether a UUID has been slightly modified to redirect a reference to another object. Humans can't easily check a UUID's integrity just by glancing at it ๐
MAC addresses come with inherent privacy risks, so they SHOULD NOT be used within a UUID. Instead, CSPRNG data SHOULD be selected from a source with sufficient entropy to guarantee uniqueness among UUID generation ๐ See Sections 6.9 and 6.10 for more info ๐ฆ
Timestamps embedded in a UUID do pose a very small attack surface ๐ธ The timestamp together with an embedded counter does signal the order of creation for a UUID and its corresponding data, but it doesn't tell you anything about the data itself or the application as a whole. If UUIDs are required for any security operation within an application context, in any shape or form, then UUIDv4 (Section 5.4) SHOULD be utilized ๐
See [RFC6151] for MD5 security considerations and [RFC6194] for SHA-1 security considerations ๐
9. References ๐
9.1. Normative References ๐ง
- [C309] "X/Open DCE: Remote Procedure Call", ISBN 1-85912-041-5, Open CAE Specification C309, August 1994,
<https://pubs.opengroup.org/onlinepubs/9696999099/toc.pdf>. - [C311] "DCE 1.1: Authentication and Security Services", Open Group CAE Specification C311, August 1997,
<https://pubs.opengroup.org/onlinepubs/9696989899/toc.pdf>. - [FIPS180-4] National Institute of Standards and Technology (NIST), "Secure Hash Standard (SHS)", FIPS PUB 180-4, DOI 10.6028/NIST.FIPS.180-4, August 2015,
<https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf>. - [FIPS202] National Institute of Standards and Technology (NIST), "SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions", FIPS PUB 202, DOI 10.6028/NIST.FIPS.202, August 2015,
<https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf>. - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997,
<https://www.rfc-editor.org/info/rfc2119>. - [RFC8141] Saint-Andre, P. and J. Klensin, "Uniform Resource Names (URNs)", RFC 8141, DOI 10.17487/RFC8141, April 2017,
<https://www.rfc-editor.org/info/rfc8141>. - [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017,
<https://www.rfc-editor.org/info/rfc8174>. - [X667] ITU-T, "Information technology - Open Systems Interconnection - Procedures for the operation of OSI Registration Authorities: Generation and registration of Universally Unique Identifiers (UUIDs) and their use as ASN.1 object identifier components", ISO/IEC 9834-8:2004, ITU-T Recommendation X.667, September 2004.
9.2. Informative References โจ
okay bestie, these are the "for vibes and receipts" references ๐ Nothing here is strictly required to implement the spec, but they're where all the good stuff lives: real-world ID generators, errata, and the standards that the rest of the doc leans on ๐ง
- [COMBGUID] "Creating sequential GUIDs in C# for MSSQL or PostgreSql", commit 2759820, December 2020,
<https://github.com/richardtallent/RT.Comb>. - [CUID] "Collision-resistant ids optimized for horizontal scaling and performance.", commit 215b27b, October 2020,
<https://github.com/ericelliott/cuid>. - [Elasticflake] Pearcy, P., "Sequential UUID / Flake ID generator pulled out of elasticsearch common", commit dd71c21, January 2015,
<https://github.com/ppearcy/elasticflake>. - [Err1957] RFC Errata, Erratum ID 1957, RFC 4122,
<https://www.rfc-editor.org/errata/eid1957>. - [Err3546] RFC Errata, Erratum ID 3546, RFC 4122,
<https://www.rfc-editor.org/errata/eid3546>. - [Err4975] RFC Errata, Erratum ID 4975, RFC 4122,
<https://www.rfc-editor.org/errata/eid4975>. - [Err4976] RFC Errata, Erratum ID 4976, RFC 4122,
<https://www.rfc-editor.org/errata/eid4976>. - [Err5560] RFC Errata, Erratum ID 5560, RFC 4122,
<https://www.rfc-editor.org/errata/eid5560>. - [Flake] Boundary, "Flake: A decentralized, k-ordered id generation service in Erlang", commit 15c933a, February 2017,
<https://github.com/boundary/flake>. - [FlakeID] "Flake ID Generator", commit fcd6a2f, April 2020,
<https://github.com/T-PWK/flake-idgen>. - [IBM_NCS] IBM, "uuid_gen Command (NCS)", March 2023,
<https://www.ibm.com/docs/en/aix/7.1?topic=u-uuid-gen-command-ncs>. - [IEEE754] IEEE, "IEEE Standard for Floating-Point Arithmetic." IEEE Std 754-2019, DOI 10.1109/IEEESTD.2019.8766229, July 2019,
<https://standards.ieee.org/ieee/754/6210/>. - [IEEE802.11bh] IEEE, "IEEE Draft Standard for Information technology-- Telecommunications and information exchange between systems Local and metropolitan area networks--Specific requirements - Part 11: Wireless LAN Medium Access Control (MAC) and Physical Layer (PHY) Specifications Amendment: Enhancements for Extremely High Throughput (EHT)", Electronic ISBN 978-1-5044-9520-2, March 2023,
<https://standards.ieee.org/ieee/802.11bh/10525/>. - [KSUID] Segment, "K-Sortable Globally Unique IDs", commit bf376a7, July 2020,
<https://github.com/segmentio/ksuid>. - [LexicalUUID] Twitter, "Cassie", commit f6da4e0, November 2012,
<https://github.com/twitter-archive/cassie>. - [Microsoft] Microsoft, "2.3.4.3 GUID - Curly Braced String Representation", April 2023,
<https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/222af2d3-5c00-4899-bc87-ed4c6515e80d>. - [MS_COM_GUID] Chen, R., "Why does COM express GUIDs in a mix of big-endian and little-endian? Why can't it just pick a side and stick with it?", September 2022,
<https://devblogs.microsoft.com/oldnewthing/20220928-00/?p=107221>. - [ObjectID] MongoDB, "ObjectId",
<https://docs.mongodb.com/manual/reference/method/ObjectId/>. - [orderedUuid] Cabrera, I. B., "Laravel: The mysterious "Ordered UUID"", January 2020,
<https://itnext.io/laravel-the-mysterious-ordered-uuid-29e7500b4f8>. - [pushID] Lehenbauer, M., "The 2^120 Ways to Ensure Unique Identifiers", February 2015,
<https://firebase.googleblog.com/2015/02/the-2120-ways-to-ensure-unique_68.html>. - [Python] Python, "uuid - UUID objects according to RFC 4122",
<https://docs.python.org/3/library/uuid.html>. - [RANDOM] Occil, P., "Random Number Generator Recommendations for Applications", June 2023,
<https://peteroupc.github.io/random.html>. - [RFC1321] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321, DOI 10.17487/RFC1321, April 1992,
<https://www.rfc-editor.org/info/rfc1321>. - [RFC1738] Berners-Lee, T., Masinter, L., and M. McCahill, "Uniform Resource Locators (URL)", RFC 1738, DOI 10.17487/RFC1738, December 1994,
<https://www.rfc-editor.org/info/rfc1738>. - [RFC4086] Eastlake 3rd, D., Schiller, J., and S. Crocker, "Randomness Requirements for Security", BCP 106, RFC 4086, DOI 10.17487/RFC4086, June 2005,
<https://www.rfc-editor.org/info/rfc4086>. - [RFC4122] Leach, P., Mealling, M., and R. Salz, "A Universally Unique IDentifier (UUID) URN Namespace", RFC 4122, DOI 10.17487/RFC4122, July 2005,
<https://www.rfc-editor.org/info/rfc4122>. - [RFC5234] Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", STD 68, RFC 5234, DOI 10.17487/RFC5234, January 2008,
<https://www.rfc-editor.org/info/rfc5234>. - [RFC6151] Turner, S. and L. Chen, "Updated Security Considerations for the MD5 Message-Digest and the HMAC-MD5 Algorithms", RFC 6151, DOI 10.17487/RFC6151, March 2011,
<https://www.rfc-editor.org/info/rfc6151>. - [RFC6194] Polk, T., Chen, L., Turner, S., and P. Hoffman, "Security Considerations for the SHA-0 and SHA-1 Message-Digest Algorithms", RFC 6194, DOI 10.17487/RFC6194, March 2011,
<https://www.rfc-editor.org/info/rfc6194>. - [RFC8126] Cotton, M., Leiba, B., and T. Narten, "Guidelines for Writing an IANA Considerations Section in RFCs", BCP 26, RFC 8126, DOI 10.17487/RFC8126, June 2017,
<https://www.rfc-editor.org/info/rfc8126>. - [RFC8937] Cremers, C., Garratt, L., Smyshlyaev, S., Sullivan, N., and C. Wood, "Randomness Improvements for Security Protocols", RFC 8937, DOI 10.17487/RFC8937, October 2020,
<https://www.rfc-editor.org/info/rfc8937>. - [RFC9499] Hoffman, P. and K. Fujiwara, "DNS Terminology", BCP 219, RFC 9499, DOI 10.17487/RFC9499, March 2024,
<https://www.rfc-editor.org/info/rfc9499>. - [RFC9542] Eastlake 3rd, D., Abley, J., and Y. Li, "IANA Considerations and IETF Protocol and Documentation Usage for IEEE 802 Parameters", BCP 141, RFC 9542, DOI 10.17487/RFC9542, April 2024,
<https://www.rfc-editor.org/info/rfc9542>. - [ShardingID] Instagram Engineering, "Sharding & IDs at Instagram", December 2012,
<https://instagram-engineering.com/sharding-ids-at-instagram-1cf5a71e5a5c>. - [SID] "sid : generate sortable identifiers", Commit 660e947, June 2019,
<https://github.com/chilts/sid>. - [Snowflake] Twitter, "Snowflake is a network service for generating unique ID numbers at high scale with some simple guarantees.", commit ec40836, May 2014,
<https://github.com/twitter-archive/snowflake>. - [Sonyflake] Sony, "A distributed unique ID generator inspired by Twitter's Snowflake", commit 848d664, August 2020,
<https://github.com/sony/sonyflake>. - [ULID] "Universally Unique Lexicographically Sortable Identifier", Commit d0c7170, May 2019,
<https://github.com/ulid/spec>. - [URNNamespaces] IANA, "Uniform Resource Names (URN) Namespaces",
<https://www.iana.org/assignments/urn-namespaces/>. - [X500] ITU-T, "Information technology - Open Systems Interconnection - The Directory: Overview of concepts, models and services", ISO/IEC 9594-1, ITU-T Recommendation X.500, October 2019.
- [X660] ITU-T, "Information technology - Procedures for the operation of object identifier registration authorities: General procedures and top arcs of the international object identifier tree", ISO/IEC 9834-1, ITU-T Recommendation X.660, July 2011.
- [X680] ITU-T, "Information Technology - Abstract Syntax Notation One (ASN.1) & ASN.1 encoding rules", ISO/IEC 8824-1:2021, ITU-T Recommendation X.680, February 2021.
- [XID] "Globally Unique ID Generator", commit efa678f, October 2020,
<https://github.com/rs/xid>.
Appendix A. Test Vectors ๐งช
okay so the test vectors are where we get to see the math in action, and it's honestly so satisfying ๐ฅน Both the UUIDv1 and UUIDv6 vectors use the same 60-bit timestamp, which is 0x1EC9414C232AB00 (138648505420000000), and that's Tuesday, February 22, 2022 2:22:22.000000 PM GMT-05:00 ๐
Both UUIDv1 and UUIDv6 use the same values in clock_seq and node, and all of those were generated with random data ๐ฒ For the randomized node, the least significant bit of the first octet is set to a value of 1 as per Section 6.10. So the starting value 0x9E6BDECED846 got changed to 0x9F6BDECED846 ๐
The pseudocode for converting a 64-bit Unix timestamp into a 100 ns Gregorian timestamp value is still in the doc, just for reference, so you can follow the steps yourself ๐ง
# Gregorian-to-Unix Offset:
# The number of 100 ns intervals between the
# UUID Epoch 1582-10-15 00:00:00
# and the Unix Epoch 1970-01-01 00:00:00
# Greg_Unix_offset = 0x01b21dd213814000 or 122192928000000000
# Unix 64-bit Nanosecond Timestamp:
# Unix NS: Tuesday, February 22, 2022 2:22:22 PM GMT-05:00
# Unix_64_bit_ns = 0x16D6320C3D4DCC00 or 1645557742000000000
# Unix Nanosecond precision to Gregorian 100-nanosecond intervals
# Greg_100_ns = (Unix_64_bit_ns/100)+Greg_Unix_offset
# Work:
# Greg_100_ns = (1645557742000000000/100)+122192928000000000
# Unix_64_bit_ns = (138648505420000000-122192928000000000)*100
# Final:
# Greg_100_ns = 0x1EC9414C232AB00 or 138648505420000000
Figure 15: Test Vector Timestamp Pseudocode
A.1. Example of a UUIDv1 Value ๐ฆ
Here's the full UUIDv1 example, field by field. It's giving clean breakdown ๐ซถ
-------------------------------------------
field bits value
-------------------------------------------
time_low 32 0xC232AB00
time_mid 16 0x9414
ver 4 0x1
time_high 12 0x1EC
var 2 0b10
clock_seq 14 0b11, 0x3C8
node 48 0x9F6BDECED846
-------------------------------------------
total 128
-------------------------------------------
final: C232AB00-9414-11EC-B3C8-9F6BDECED846
Figure 16: UUIDv1 Example Test Vector
A.2. Example of a UUIDv3 Value
okay so this one is the UUIDv3 example and it's giving MD5 realness ๐ we hash the DNS Namespace ID together with the Name "www.example.com" (that's Figure 17) โจ then Figure 18 shows the field mapping and every value laid out bit by bit ๐ฆ and if you want to see the version and variant bit swaps up close, Figure 19 has you covered ๐
Namespace (DNS): 6ba7b810-9dad-11d1-80b4-00c04fd430c8
Name: www.example.com
------------------------------------------------------
MD5: 5df418813aed051548a72f4a814cf09e
Figure 17: UUIDv3 Example MD5
-------------------------------------------
field bits value
-------------------------------------------
md5_high 48 0x5df418813aed
ver 4 0x3
md5_mid 12 0x515
var 2 0b10
md5_low 62 0b00, 0x8a72f4a814cf09e
-------------------------------------------
total 128
-------------------------------------------
final: 5df41881-3aed-3515-88a7-2f4a814cf09e
Figure 18: UUIDv3 Example Test Vector
MD5 hex and dash: 5df41881-3aed-0515-48a7-2f4a814cf09e
Ver and Var Overwrite: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
Final: 5df41881-3aed-3515-88a7-2f4a814cf09e
Figure 19: UUIDv3 Example Ver/Var Bit Swaps
A.3. Example of a UUIDv4 Value
this UUIDv4 example is the random one ๐ฒโจ the creator grabbed 16 bytes of random data and got the hex value 919108F752D133205BACF847DB4148A8 (so random, so iconic ๐คฉ) then those bytes get poured into the fields you see in Figure 20 ๐
Then, to show off the version and variant bit swaps, check out Figure 21 ๐ฆ
-------------------------------------------
field bits value
-------------------------------------------
random_a 48 0x919108f752d1
ver 4 0x4
random_b 12 0x320
var 2 0b10
random_c 62 0b01, 0xbacf847db4148a8
-------------------------------------------
total 128
-------------------------------------------
final: 919108f7-52d1-4320-9bac-f847db4148a8
Figure 20: UUIDv4 Example Test Vector
Random hex: 919108f752d133205bacf847db4148a8
Random hex and dash: 919108f7-52d1-3320-5bac-f847db4148a8
Ver and Var Overwrite: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
Final: 919108f7-52d1-4320-9bac-f847db4148a8
Figure 21: UUIDv4 Example Ver/Var Bit Swaps
A.4. Example of a UUIDv5 Value
this one is UUIDv5, the SHA-1 version ๐งฉ we use the DNS Namespace ID and the Name "www.example.com" for the computation in Figure 22 ๐ the field mapping and every value are in Figure 23 โจ and then Figure 24 is the one that gets extra spicy, because it shows the version and variant bit swaps AND the leftover part of the SHA-1 value that gets thrown away ๐
Namespace (DNS): 6ba7b810-9dad-11d1-80b4-00c04fd430c8
Name: www.example.com
----------------------------------------------------------
SHA-1: 2ed6657de927468b55e12665a8aea6a22dee3e35
Figure 22: UUIDv5 Example SHA-1
-------------------------------------------
field bits value
-------------------------------------------
sha1_high 48 0x2ed6657de927
ver 4 0x5
sha1_mid 12 0x68b
var 2 0b10
sha1_low 62 0b01, 0x5e12665a8aea6a2
-------------------------------------------
total 128
-------------------------------------------
final: 2ed6657d-e927-568b-95e1-2665a8aea6a2
Figure 23: UUIDv5 Example Test Vector
SHA-1 hex and dash: 2ed6657d-e927-468b-55e1-2665a8aea6a2-2dee3e35
Ver and Var Overwrite: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
Final: 2ed6657d-e927-568b-95e1-2665a8aea6a2
Discarded: -2dee3e35
Figure 24: UUIDv5 Example Ver/Var Bit Swaps and Discarded SHA-1
Segment
A.5. Example of a UUIDv6 Value
here's the UUIDv6 test vector ๐ธ the timestamp gets split up into its pieces, and the version and variant bits get slotted in right where they belong โจ
-------------------------------------------
field bits value
-------------------------------------------
time_high 32 0x1EC9414C
time_mid 16 0x232A
ver 4 0x6
time_high 12 0xB00
var 2 0b10
clock_seq 14 0b11, 0x3C8
node 48 0x9F6BDECED846
-------------------------------------------
total 128
-------------------------------------------
final: 1EC9414C-232A-6B00-B3C8-9F6BDECED846
Figure 25: UUIDv6 Example Test Vector
A.6. Example of a UUIDv7 Value
this UUIDv7 test vector is giving clean timestamp energy ๐ฐ๏ธ๐ it uses a well-known Unix Epoch timestamp with millisecond precision to fill the first 48 bits ๐ง
rand_a and rand_b get filled with random data ๐ฒ
the timestamp is Tuesday, February 22, 2022 2:22:22.00 PM GMT-05:00, which is 0x017F22E279B0 or 1645557742000 in the hex and decimal versions ๐
-------------------------------------------
field bits value
-------------------------------------------
unix_ts_ms 48 0x017F22E279B0
ver 4 0x7
rand_a 12 0xCC3
var 2 0b10
rand_b 62 0b01, 0x8C4DC0C0C07398F
-------------------------------------------
total 128
-------------------------------------------
final: 017F22E2-79B0-7CC3-98C4-DC0C0C07398F
Figure 26: UUIDv7 Example Test Vector
Appendix B. Illustrative Examples
these sections are all about how you can use UUIDv8 (Section 5.8) for custom and/or experimental, application-based logic ๐ ๏ธโจ quick heads-up though: these examples have NOT been through the same rigorous testing, prototyping, and feedback loop as the other algorithms in this document ๐ the authors really encourage implementers to create their own UUIDv8 algorithm instead of just using the ones in this section ๐
B.1. Example of a UUIDv8 Value (Time-Based)
this UUIDv8 test vector uses a well-known 64-bit Unix Epoch timestamp with 10 ns precision ๐ it gets truncated to its least significant, rightmost bits to fill the first 60 bits of custom_a and custom_b, while the version bits sit between those two segments and get set to the version value of 8 ๐
the variant bits get set too, and the final segment, custom_c, is filled with random data ๐ฒ
the timestamp is Tuesday, February 22, 2022 2:22:22.000000 PM GMT-05:00, which is 0x2489E9AD2EE2E00 or 164555774200000000 (in 10 ns steps) โญ
-------------------------------------------
field bits value
-------------------------------------------
custom_a 48 0x2489E9AD2EE2
ver 4 0x8
custom_b 12 0xE00
var 2 0b10
custom_c 62 0b00, 0xEC932D5F69181C0
-------------------------------------------
total 128
-------------------------------------------
final: 2489E9AD-2EE2-8E00-8EC9-32D5F69181C0
Figure 27: UUIDv8 Example Time-Based Illustrative Example
B.2. Example of a UUIDv8 Value (Name-Based)
okay so per Section 5.5, name-based UUIDs that want to use modern hashing algorithms MUST be created within the UUIDv8 space ๐ง these MAY leverage newer hashing algorithms like SHA-256 or SHA-512 (as defined by [FIPS180-4]), SHA-3 or SHAKE (as defined by [FIPS202]), or even algorithms that haven't been defined yet ๐ฎ
the SHA-256 version of the SHA-1 computation from Appendix A.4 is in Figure 28, as an illustrative example of how this can be done ๐ the creation of the name-based UUIDv8 value here follows the exact same logic as Section 5.5, with SHA-256 swapped in for SHA-1 ๐ฆ
the field mapping and all values are in Figure 29 โจ and Figure 30 shows the version and variant bit swaps along with the unused/discarded part of the SHA-256 value ๐ big important note: for secure hashing algorithms that produce outputs of an arbitrary size, such as the ones in SHAKE, the output hash MUST be 128 bits or larger ๐จ
Namespace (DNS): 6ba7b810-9dad-11d1-80b4-00c04fd430c8
Name: www.example.com
----------------------------------------------------------------
SHA-256:
5c146b143c524afd938a375d0df1fbf6fe12a66b645f72f6158759387e51f3c8
Figure 28: UUIDv8 Example SHA256
-------------------------------------------
field bits value
-------------------------------------------
custom_a 48 0x5c146b143c52
ver 4 0x8
custom_b 12 0xafd
var 2 0b10
custom_c 62 0b00, 0x38a375d0df1fbf6
-------------------------------------------
total 128
-------------------------------------------
final: 5c146b14-3c52-8afd-938a-375d0df1fbf6
Figure 29: UUIDv8 Example Name-Based SHA-256 Illustrative Example
A: 5c146b14-3c52-4afd-938a-375d0df1fbf6-fe12a66b645f72f6158759387e51f3c8
B: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
C: 5c146b14-3c52-8afd-938a-375d0df1fbf6
D: -fe12a66b645f72f6158759387e51f3c8
Figure 30: UUIDv8 Example Ver/Var Bit Swaps and Discarded SHA-256
Segment
Examining Figure 30, with the lines broken down:
- Line A details the full SHA-256 as a hexadecimal value with the dashes inserted. ๐
- Line B details the version and variant hexadecimal positions, which must be overwritten. ๐ซถ
- Line C details the final value after the ver and var have been overwritten. ๐
- Line D details the discarded leftover values from the original SHA-256 computation. ๐๏ธ
Acknowledgements
the authors gratefully acknowledge the contributions of Rich Salz, Michael Mealling, Ben Campbell, Ben Ramsey, Fabio Lima, Gonzalo Salgueiro, Martin Thomson, Murray S. Kucherawy, Rick van Rein, Rob Wilton, Sean Leonard, Theodore Y. Ts'o, Robert Kieffer, Sergey Prokhorenko, and LiosK ๐ซถ
as well as everyone in the IETF community and on GitHub who contributed to the discussions that led to this document ๐
this document draws heavily on the OSF DCE specification (Appendix A of [C309]) for UUIDs ๐ Ted Ts'o gave helpful comments ๐
we're also so grateful to the careful reading and bit-twiddling of Ralf S. Engelschall, John Larmouth, and Paul Thorpe ๐ค Professor Larmouth was also invaluable in achieving coordination with ISO/IEC ๐
Authors' Addresses
Kyzer R. Davis Cisco Systems Email: kydavis@cisco.com
Brad G. Peabody Uncloud Email: brad@peabody.io
Paul J. Leach University of Washington Email: pjl7@uw.edu
๐ฆ where this page comes from
- ietf: rfc9562 2024-05
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms