Repository: uuid6/uuid6-ietf-draft Branch: master Commit: 35ec1548920d Files: 26 Total size: 1.4 MB Directory structure: gitextract_2x_pp6_7/ ├── .github/ │ └── ISSUE_TEMPLATE/ │ └── proposed-draft-change.md ├── .gitignore ├── README.md ├── draft-peabody-dispatch-new-uuid-format-04.html ├── draft-peabody-dispatch-new-uuid-format-04.txt ├── draft-peabody-dispatch-new-uuid-format-04.xml ├── editor-notes/ │ ├── LATEST-OUTLINE.md │ └── LATEST.md ├── index.html ├── old drafts/ │ ├── .gitignore │ ├── README.md │ ├── draft-peabody-dispatch-new-uuid-format-00.txt │ ├── draft-peabody-dispatch-new-uuid-format-00.xml │ ├── draft-peabody-dispatch-new-uuid-format-01.html │ ├── draft-peabody-dispatch-new-uuid-format-01.txt │ ├── draft-peabody-dispatch-new-uuid-format-01.xml │ ├── draft-peabody-dispatch-new-uuid-format-02.html │ ├── draft-peabody-dispatch-new-uuid-format-02.txt │ ├── draft-peabody-dispatch-new-uuid-format-02.xml │ ├── draft-peabody-dispatch-new-uuid-format-03.html │ ├── draft-peabody-dispatch-new-uuid-format-03.txt │ ├── draft-peabody-dispatch-new-uuid-format-03.xml │ ├── draft-peabody-dispatch-new-uuid-format.txt │ └── draft-peabody-dispatch-new-uuid-format.xml └── research/ ├── sortable-id-analysis.md └── sortable-id-comparisons.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/ISSUE_TEMPLATE/proposed-draft-change.md ================================================ --- name: Proposed Draft Change about: XML Draft Changes title: '' labels: Change Proposal assignees: kyzer-davis --- # Change Proposal Template #### Source (Select one.) - [ ] IETF Published Draft - [ ] Work in Progress Draft #### Change Reason (Select all that apply.) - [ ] Typos and grammatical issues - [ ] Bad Reference - [ ] IETF Verbiage modification (MAY, MUST, SHOULD, SHOULD NOT, etc) - [ ] New Text for additional context - [ ] Underlying XML Format Update - [ ] ASCII diagram updates (artwork, code samples, etc.) #### Draft Number, Full Section, Name ``` Draft 02, Section 5.1. Timestamp Granularity ``` #### Current Text: ``` UUIDs MAY be universally unique. ``` #### Proposed Text: ``` UUIDs SHOULD be universally unique. ``` --- ### Other Supporting information below: Insert data here ================================================ FILE: .gitignore ================================================ misc-notes.txt ================================================ FILE: README.md ================================================ # Final ``` RFC 9562 Title: Universally Unique IDentifiers (UUIDs) Author: K. Davis, B. Peabody, P. Leach Status: Standards Track Stream: IETF Date: May 2024 Mailbox: kydavis@cisco.com, brad@peabody.io, pjl7@uw.edu Pages: 46 Obsoletes: RFC 4122 I-D Tag: draft-ietf-uuidrev-rfc4122bis-14.txt URL: https://www.rfc-editor.org/info/rfc9562 DOI: 10.17487/RFC9562 ``` # Updates - This work has been officially adopted by the IETF! - Work on the base document has been reset to Draft 00 and moved to https://github.com/ietf-wg-uuidrev/rfc4122bis - Full Details and further updates will be posted in [Post-IETF 114 and the future of this Draft](https://github.com/uuid6/uuid6-ietf-draft/issues/122) ``` Name: draft-ietf-uuidrev-rfc4122bis Revision: 14 Title: Universally Unique IDentifiers (UUID) Date: 2023-11-06 Group: uuidrev Pages: 58 URL: https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-14.txt Status: https://datatracker.ietf.org/doc/draft-ietf-uuidrev-rfc4122bis/ HTML: https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-14.html HTMLized: https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis Diff: https://author-tools.ietf.org/iddiff?url2=draft-ietf-uuidrev-rfc4122bis-14 ``` --- # New UUID Formats This is the GitHub repo for the IETF draft surrounding the topic of new UUID formats. Various discussion will need to occur to arrive at a standard and this repo will be used to collect and organize that information. ## High Level Overview 1. **UUID version 6**: A re-ordering of UUID version 1 so it is sortable as an opaque sequence of bytes. Easy to implement given an existing UUIDv1 implementation. `time_high|time_mid|time_low_and_version|clk_seq_hi_res|clk_seq_low|node` 2. **UUID version 7**: An entirely new time-based UUID bit layout sourced from the widely implemented and well known Unix Epoch timestamp source. `unix_ts_ms|ver|rand_a|var|rand_b` 3. **UUID version 8**: A free-form UUID format which has no explicit requirements except maintaining backward compatibility. `custom_a|ver|custom_b|var|custom_c` 5. **Max UUID**: A specialized UUID which is the inverse of the Nil UUID from RFC4122. `FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF` --- # RFC Scope In order to keep things on track the following topics have been decided as in-scope or out of scope for this particular RFC. For more information on any of these items refer to the XML, TXT, HTML draft, research and the issue tracker for a particular discussion (follow hyperlinks below.) ### In Scope Topics - UUID Generation - [Timestamp Granularity](https://github.com/uuid6/uuid6-ietf-draft/issues/23) - Sub-Topics: Timestamp epoch source, format, length, accuracy and bit layout - [Monotonicity and Counters for same Timestamp-tick collision avoidance during batch UUID creation](https://github.com/uuid6/uuid6-ietf-draft/issues/60) - Sub-Topics: Counter position, length, rollover handling and seeding. - [Pseudo-random formatting, length and generation methods](https://github.com/uuid6/uuid6-ietf-draft/issues/55) - Distributed UUID Generation best practices - Sub-Topics: [Shared Knowledge Schemes and embedded nondescript node identifiers](https://github.com/uuid6/uuid6-ietf-draft/issues/36) - [Max UUID Usage](https://github.com/uuid6/uuid6-ietf-draft/issues/62) ### In Scope Topics - UUID Best Practices as it relates to the previous topics - Global and Local Uniqueness (collision resistance mechanisms) - Unguessability - Sorting/Ordering techniques - Storage and Opacity best practices - Big Endian vs Little Endian bit layout - Any and all UUID security concerns! - Sub-Topics: [MAC address usage in next-generation UUIDs](https://github.com/uuid6/uuid6-ietf-draft/issues/13) --- ### Out of Scope Topics (Rolled into a new Draft that can be found here: [New UUID Encoding Techniques](https://github.com/uuid6/new-uuid-encoding-techniques-ietf-draft)) - [URN Modifications](https://github.com/uuid6/new-uuid-encoding-techniques-ietf-draft/issues/4) - [Alternative text encoding techniques (Crockfords Base32, Base64, etc)](https://github.com/uuid6/new-uuid-encoding-techniques-ietf-draft/issues/3) - [Variable length UUIDs | UUID Long](https://github.com/uuid6/new-uuid-encoding-techniques-ietf-draft/issues/2) ### Out of Scope Topics - [Variant Bit E Usage](https://github.com/uuid6/uuid6-ietf-draft/issues/26) --- ### Out of Scope Topics (as as the result of discussion threads) - [Variable length subsecond precision encoding](https://github.com/uuid6/uuid6-ietf-draft/issues/24) ### Out of Scope Topics (for backwards compatibility) - Changing the default 8-4-4-4-12 UUID text layout - Changing anything about RFC4122's UUID versions 1 through 5 - [Changing too much about UUIDv6 that would otherwise inhibit porting v1 to v6](https://github.com/uuid6/uuid6-ietf-draft/issues/52) --- # Contributing - The XML draft in the root folder is the most recent working draft for re-submission to the IETF. - An HTML and Textual (.txt) RFC representation will be provided in the root folder to ease reader input and discussion. - [Older drafts](https://github.com/uuid6/uuid6-ietf-draft/tree/master/old%20drafts) are available for view here or on the [IETF Datatracker](https://datatracker.ietf.org/doc/draft-peabody-dispatch-new-uuid-format/). - The RFC Draft utilize an XML formatted document that follows [RFC7742 markup](https://xml2rfc.tools.ietf.org/rfc7749.html). All XML changes MUST follow this format and pass conversion to `.txt` and `.html` via https://xml2rfc.tools.ietf.org/ - Utilize the issue tracker to discuss topics, solutions, problems, typos and anything else. - Where possible contribute to an existing [Discussion Thread](https://github.com/uuid6/uuid6-ietf-draft/issues?q=is%3Aissue+is%3Aopen+label%3ADiscussion) vs creating a new thread. - Reviewing is the pre-Draft 01 [Research efforts](https://github.com/uuid6/uuid6-ietf-draft/tree/master/research) is encouraged before diving into discussion threads. - New threads that propose alternative text SHOULD utilize `Proposed Draft Change` GitHub issue template to ensure proper information is captured for the draft authors. - Be civil! - Pull requests will be accepted *as long as the text is concise, clear and objective.* - PRs will not be accepted for changes to the decision made for the draft without full discussion. - PRs MUST include the updated `.xml` and xml2rfc generated `.txt` and `.html` documents. - Draft versions are frozen until submission to the IETF; at which point new work constitutes a new draft version. --- # Prototyping Remember first and foremost that this specification is still a draft. Breaking changes are to be expected. Prototypes SHOULD only be implemented to verify or discredit topics of the draft text. - [Prototype Implementations](https://github.com/uuid6/prototypes) are available via this repro. ================================================ FILE: draft-peabody-dispatch-new-uuid-format-04.html ================================================
| Internet-Draft | new-uuid-format | June 2022 |
| Peabody & Davis | Expires 25 December 2022 | [Page] |
This document presents new Universally Unique Identifier (UUID) formats for use in modern applications and databases.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 25 December 2022.¶
Copyright (c) 2022 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) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
Many things have changed in the time since UUIDs were originally created. Modern applications have a need to create and utilize UUIDs as the primary identifier for a variety of different items in complex computational systems, including but not limited to database keys, file names, machine or system names, and identifiers for event-driven transactions.¶
One area UUIDs have gained popularity is as database keys. This stems from the increasingly distributed nature of modern applications. In such cases, "auto increment" schemes often used by databases do not work well, as the effort required to coordinate unique numeric identifiers across a network can easily become a burden. The fact that UUIDs can be used to create unique, reasonably short values in distributed systems without requiring synchronization makes them a good alternative, but UUID versions 1-5 lack certain other desirable characteristics:¶
Non-time-ordered UUID versions such as UUIDv4 have poor database index locality. Meaning new values created in succession are not close to each other in the index and thus require inserts to be performed at random locations. The negative performance effects of which on common structures used for this (B-tree and its variants) can be dramatic.¶
The 100-nanosecond, Gregorian epoch used in UUIDv1 timestamps is uncommon and difficult to represent accurately using a standard number format such as [IEEE754].¶
Introspection/parsing is required to order by time sequence; as opposed to being able to perform a simple byte-by-byte comparison.¶
Privacy and network security issues arise from using a MAC address in the node field of Version 1 UUIDs. Exposed MAC addresses can be used as an attack surface to locate machines and reveal various other information about such machines (minimally manufacturer, potentially other details). Additionally, with the advent of virtual machines and containers, MAC address uniqueness is no longer guaranteed.¶
Many of the implementation details specified in [RFC4122] involve trade offs that are neither possible to specify for all applications nor necessary to produce interoperable implementations.¶
[RFC4122] does not distinguish between the requirements for generation of a UUID versus an application which simply stores one, which are often different.¶
Due to the aforementioned issue, many widely distributed database applications and large application vendors have sought to solve the problem of creating a better time-based, sortable unique identifier for use as a database key. This has lead to numerous implementations over the past 10+ years solving the same problem in slightly different ways.¶
While preparing this specification the following 16 different implementations were analyzed for trends in total ID length, bit Layout, lexical formatting/encoding, timestamp type, timestamp format, timestamp accuracy, node format/components, collision handling and multi-timestamp tick generation sequencing.¶
[LexicalUUID] by Twitter¶
[ShardingID] by Instagram¶
[Elasticflake] by P. Pearcy¶
[orderedUuid] by IT. Cabrera¶
An inspection of these implementations and the issues described above has led to this document which attempts to adapt UUIDs to address these issues.¶
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.¶
The following UUIDs are hereby introduced:¶
RFC EDITOR PLEASE DELETE THIS SECTION.¶
draft-04¶
- Fixed bad title in IEEE754 Normative Reference¶
- Fixed bad GMT offset in Test Vector Appendix¶
- Removed MAY in Counters section¶
- Condensed Counter Type into Counter Methods to reduce text¶
- Removed option for random increment along with fixed-length counter¶
- Described how to handle scenario where New UUID less than Old UUID¶
- Allow timestamp increment if counter overflows¶
- Replaced UUIDv8 C code snippet with full generation example¶
- Fixed RFC4086 Reference link¶
- Describe reseeding best practice for CSPRNG¶
- Changed MUST to SHOULD removing requirement for absolute monotonicity¶
draft-03¶
- Reworked the draft body to make the content more concise¶
- UUIDv6 section reworked to just the reorder of the timestamp¶
- UUIDv7 changed to simplify timestamp mechanism to just millisecond Unix timestamp¶
- UUIDv8 relaxed to be custom in all elements except version and variant¶
- Introduced Max UUID.¶
- Added C code samples in Appendix.¶
- Added test vectors in Appendix.¶
- Version and Variant section combined into one section.¶
- Changed from pseudo-random number generators to cryptographically secure pseudo-random number generator (CSPRNG).¶
- Combined redundant topics from all UUIDs into sections such as Timestamp granularity, Monotonicity and Counters, Collision Resistance, Sorting, and Unguessability, etc.¶
- Split Encoding and Storage into Opacity and DBMS and Database Considerations¶
- Reworked Global Uniqueness under new section Global and Local Uniqueness¶
- Node verbiage only used in UUIDv6 all others reference random/rand instead¶
- Clock sequence verbiage changed simply to counter in any section other than UUIDv6¶
- Added Abbreviations section¶
- Updated IETF Draft XML Layout¶
- Added information about little-endian UUIDs¶
draft-02¶
- Added Changelog¶
- Fixed misc. grammatical errors¶
- Fixed section numbering issue¶
- Fixed some UUIDvX reference issues¶
- Changed all instances of "motonic" to "monotonic"¶
- Changed all instances of "#-bit" to "# bit"¶
- Changed "proceeding" verbiage to "after" in section 7¶
- Added details on how to pad 32 bit Unix timestamp to 36 bits in UUIDv7¶
- Added details on how to truncate 64 bit Unix timestamp to 36 bits in UUIDv7¶
- Added forward reference and bullet to UUIDv8 if truncating 64 bit Unix Epoch is not an option.¶
- Fixed bad reference to non-existent "time_or_node" in section 4.5.4¶
draft-01¶
- Complete rewrite of entire document.¶
- The format, flow and verbiage used in the specification has been reworked to mirror the original RFC 4122 and current IETF standards.¶
- Removed the topics of UUID length modification, alternate UUID text formats, and alternate UUID encoding techniques.¶
- Research into 16 different historical and current implementations of time-based universal identifiers was completed at the end of 2020 in attempt to identify trends which have directly influenced design decisions in this draft document (https://github.com/uuid6/uuid6-ietf-draft/tree/master/research)¶
- Prototype implementation have been completed for UUIDv6, UUIDv7, and UUIDv8 in various languages by many GitHub community members. (https://github.com/uuid6/prototypes)¶
The variant bits utilized by UUIDs in this specification remain in the same octet as originally defined by [RFC4122], Section 4.1.1.¶
The next table details Variant 10xx (8/9/A/B) and the new versions defined by this specification. A complete guide to all versions within this variant has been includes in Appendix C.1.¶
| Msb0 | Msb1 | Msb2 | Msb3 | Version | Description |
| 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 |
For UUID version 6, 7 and 8 the variant field placement from [RFC4122] are unchanged. An example version/variant layout for UUIDv6 follows the table where M is the version and N is the variant.¶
00000000-0000-6000-8000-000000000000 00000000-0000-6000-9000-000000000000 00000000-0000-6000-A000-000000000000 00000000-0000-6000-B000-000000000000 xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
The UUID format is 16 octets; the variant bits in conjunction with the version bits described in the next section in determine finer structure.¶
UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality. It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs. Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 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 [RFC4122], Section 4.1.4, 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 bits remain unchanged from their usage and position in [RFC4122], Section 4.1.5.¶
The 48 bit node SHOULD be set to a pseudo-random value however implementations MAY choose to retain the old MAC address behavior from [RFC4122], Section 4.1.6 and [RFC4122], Section 4.5. 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 1¶
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 | time_low_and_version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|clk_seq_hi_res | clk_seq_low | node (0-1) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| node (2-5) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
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.¶
UUID version 7 features a time-ordered value field derived from the widely implemented and well known Unix Epoch timestamp source, the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded. As well as improved entropy characteristics over versions 1 or 6.¶
Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 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 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
UUID version 8 provides an RFC-compatible format for experimental or vendor-specific use cases. The only requirement is that the variant and version bits MUST be set as defined in Section 4. UUIDv8's uniqueness will be implementation-specific and SHOULD NOT be assumed.¶
The only explicitly defined bits are the Version and Variant leaving 122 bits for implementation specific time-based UUIDs. To be clear: UUIDv8 is not a replacement for UUIDv4 where all 122 extra bits are filled with random data.¶
Some example situations in which UUIDv8 usage could occur:¶
An implementation would like to embed extra information within the UUID other than what is defined in this document.¶
An implementation has other application/language restrictions which inhibit the use of one of the current UUIDs.¶
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 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The Max UUID is 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 Nil UUID defined in [RFC4122], Section 4.1.7¶
FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF
The minimum requirements for generating UUIDs are described in this document for each version. Everything else is an implementation detail and up to the implementer to decide what is appropriate for a given implementation. That being said, various relevant factors are covered below to help guide an implementer through the different trade-offs among differing UUID implementations.¶
UUID timestamp source, precision and length was the topic of great debate while creating this specification. As such choosing the right timestamp for your application is a very important topic. This section will detail some of the most common points on this topic.¶
Monotonicity is the backbone of time-based sortable UUIDs. Naturally time-based UUIDs from this document will be monotonic due to an embedded timestamp however implementations can guarantee additional monotonicity via the concepts covered in this section.¶
Additionally, care SHOULD be taken to ensure UUIDs generated in batches are also monotonic. That is, if one-thousand UUIDs are generated for the same timestamp; there is sufficient logic for organizing the creation order of those one-thousand UUIDs. For batch UUID creation implementions MAY utilize a monotonic counter which SHOULD increment for each UUID created during a given timestamp.¶
For single-node UUID implementations that do not need to create batches of UUIDs, the embedded timestamp within UUID version 1, 6, and 7 can provide sufficient monotonicity guarantees by simply ensuring that timestamp increments before creating a new UUID. For the topic of Distributed Nodes please refer to Section 6.3¶
Implementations SHOULD choose one method for single-node UUID implementations that require batch UUID creation.¶
The following sub-topics cover topics related solely with creating reliable fixed-length dedicated counters:¶
The following sub-topics cover rollover handling with either type of counter method:¶
Implementations MAY use the following logic to ensure UUIDs featuring 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; re-initialize the desired counter method to the new timestamp and generate new random bytes (if the bytes were frozen or being used as the seed for a monotonic counter).¶
Implementations SHOULD check if the the currently generated UUID is greater than the previously generated UUID. If this is not the case then any number of things could have occurred. Such as, but not limited to, clock rollbacks, leap second handling or counter rollovers. Applications SHOULD embed sufficient logic to catch these scenarios and correct the problem ensuring the next UUID generated is greater than the previous. To handle this scenario, the general guidance is that application MAY reuse the previous timestamp and increment the previous counter method.¶
Implementations SHOULD weigh the consequences of UUID collisions within their application and when deciding between UUID versions that use entropy (random) versus the other components such as Section 6.1 and Section 6.2. This is especially true for distributed node collision resistance as defined by Section 6.3.¶
There are two example scenarios below which help illustrate the varying seriousness of a collision within an application.¶
UUIDs created by this specification MAY be used to provide local uniqueness guarantees. For example, ensuring UUIDs created within a local application context are unique within a database MAY be sufficient for some implementations where global uniqueness outside of the application context, in other applications, or around the world is not required.¶
Although true global uniqueness is impossible to guarantee without a shared knowledge scheme; a shared knowledge scheme is not required by UUID to provide uniqueness guarantees. Implementations MAY implement a shared knowledge scheme introduced in Section 6.3 as they see fit to extend the uniqueness guaranteed this specification and [RFC4122].¶
Implementations SHOULD utilize a cryptographically secure pseudo-random number generator (CSPRNG) to provide values that are both difficult to predict ("unguessable") and have a low likelihood of collision ("unique"). Care SHOULD be taken to ensure the CSPRNG state is properly reseeded upon state changes, such as process forks, to ensure proper CSPRNG operation. CSPRNG ensures the best of Section 6.4 and Section 8 are present in modern UUIDs.¶
Advice on generating cryptographic-quality random numbers can be found in [RFC4086]¶
UUIDv6 and UUIDv7 are designed so that implementations that require sorting (e.g. database indexes) SHOULD sort as opaque raw bytes, without need for parsing or introspection.¶
Time ordered monotonic UUIDs benefit from greater database index locality because the new values are near each other in the index. As a result objects are more easily clustered together for better performance. The real-world differences in this approach of index locality vs random data inserts can be quite large.¶
UUIDs formats created by this specification SHOULD be Lexicographically sortable while in the textual representation.¶
UUIDs created by this specification are crafted with big-ending byte order (network byte order) in mind. If Little-endian style is required a custom UUID format SHOULD be created using UUIDv8.¶
UUIDs SHOULD be treated as opaque values and implementations SHOULD NOT examine the bits in a UUID to whatever extent is possible. However, where necessary, inspectors should refer to Section 4 for more information on determining UUID version and variant.¶
For many applications, such as databases, storing UUIDs as text is unnecessarily verbose, requiring 288 bits to represent 128 bit UUID values. Thus, where feasible, UUIDs SHOULD be stored within database applications as the underlying 128 bit binary value.¶
For other systems, UUIDs MAY be stored in binary form or as text, as appropriate. The trade-offs to both approaches are as such:¶
Storing as binary requires less space and may result in faster data access.¶
Storing as text requires more space but may require less translation if the resulting text form is to be used after retrieval and thus maybe simpler to implement.¶
DBMS vendors are encouraged to provide functionality to generate and store UUID formats defined by this specification for use as identifiers or left parts of identifiers such as, but not limited to, primary keys, surrogate keys for temporal databases, foreign keys included in polymorphic relationships, and keys for key-value pairs in JSON columns and key-value databases. Applications using a monolithic database may find using database-generated UUIDs (as opposed to client-generate UUIDs) provides the best UUID monotonicity. In addition to UUIDs, additional identifiers MAY be used to ensure integrity and feedback.¶
This document has no IANA actions.¶
MAC addresses pose inherent security risks and SHOULD not be used within a UUID. Instead CSPRNG data SHOULD be selected from a source with sufficient entropy to ensure guaranteed uniqueness among UUID generation. See Section 6.6 for more information.¶
Timestamps embedded in the UUID do pose a very small attack surface. The timestamp in conjunction with an embedded counter does signal the order of creation for a given UUID and it's corresponding data but does not define anything about the data itself or the application as a whole. If UUIDs are required for use with any security operation within an application context in any shape or form then [RFC4122] UUIDv4 SHOULD be utilized.¶
The authors gratefully acknowledge the contributions of 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, sergeyprokhorenko, LiosK As well as all of those in the IETF community and on GitHub to who contributed to the discussions which resulted in this document.¶
This section details a function in C which converts from a UUID version 1 to version 6:¶
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <arpa/inet.h>
#include <uuid/uuid.h>
/* Converts UUID version 1 to version 6 in place. */
void uuidv1tov6(uuid_t u) {
uint64_t ut;
unsigned char *up = (unsigned char *)u;
// load ut with the first 64 bits of the UUID
ut = ((uint64_t)ntohl(*((uint32_t*)up))) << 32;
ut |= ((uint64_t)ntohl(*((uint32_t*)&up[4])));
// dance the bit-shift...
ut =
((ut >> 32) & 0x0FFF) | // 12 least significant bits
(0x6000) | // version number
((ut >> 28) & 0x0000000FFFFF0000) | // next 20 bits
((ut << 20) & 0x000FFFF000000000) | // next 16 bits
(ut << 52); // 12 most significant bits
// store back in UUID
*((uint32_t*)up) = htonl((uint32_t)(ut >> 32));
*((uint32_t*)&up[4]) = htonl((uint32_t)(ut));
}
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
// ...
// csprng data source
FILE *rndf;
rndf = fopen("/dev/urandom", "r");
if (rndf == 0) {
printf("fopen /dev/urandom error\n");
return 1;
}
// ...
// generate one UUIDv7E
uint8_t u[16];
struct timespec ts;
int ret;
ret = clock_gettime(CLOCK_REALTIME, &ts);
if (ret != 0) {
printf("clock_gettime error: %d\n", ret);
return 1;
}
uint64_t tms;
tms = ((uint64_t)ts.tv_sec) * 1000;
tms += ((uint64_t)ts.tv_nsec) / 1000000;
memset(u, 0, 16);
fread(&u[6], 10, 1, rndf); // fill everything after the timestamp with random bytes
*((uint64_t*)(u)) |= htonll(tms << 16); // shift time into first 48 bits and OR into place
u[8] = 0x80 | (u[8] & 0x3F); // set variant field, top two bits are 1, 0
u[6] = 0x70 | (u[6] & 0x0F); // set version field, top four bits are 0, 1, 1, 1
UUIDv8 will vary greatly from implementation to implementation.¶
The following example utilizes:¶
32 bit custom-epoch timestamp (seconds elapsed since 2020-01-01 00:00:00 UTC)¶
16 bit exotic resolution (~15 microsecond) subsecond timestamp encoded using the fractional representation¶
58 bit random number¶
8 bit application-specific unique node ID¶
8 bit rolling sequence number¶
#include <stdint.h>
#include <time.h>
int get_random_bytes(uint8_t *buffer, int count) {
// ...
}
int generate_uuidv8(uint8_t *uuid, uint8_t node_id) {
struct timespec tp;
if (clock_gettime(CLOCK_REALTIME, &tp) != 0)
return -1; // real-time clock error
// 32 bit biased timestamp (seconds elapsed since 2020-01-01 00:00:00 UTC)
uint32_t timestamp_sec = tp.tv_sec - 1577836800;
uuid[0] = timestamp_sec >> 24;
uuid[1] = timestamp_sec >> 16;
uuid[2] = timestamp_sec >> 8;
uuid[3] = timestamp_sec;
// 16 bit subsecond fraction (~15 microsecond resolution)
uint16_t timestamp_subsec = ((uint64_t)tp.tv_nsec << 16) / 1000000000;
uuid[4] = timestamp_subsec >> 8;
uuid[5] = timestamp_subsec;
// 58 bit random number and required ver and var fields
if (get_random_bytes(&uuid[6], 8) != 0)
return -1; // random number generator error
uuid[6] = 0x80 | (uuid[6] & 0x0f);
uuid[8] = 0x80 | (uuid[8] & 0x3f);
// 8 bit application-specific node ID to guarantee application-wide uniqueness
uuid[14] = node_id;
// 8 bit rolling sequence number to help ensure process-wide uniqueness
static uint8_t sequence = 0;
uuid[15] = sequence++; // NOTE: unprotected from race conditions
return 0;
}
Both UUIDv1 and UUIDv6 test vectors utilize the same 60 bit timestamp: 0x1EC9414C232AB00 (138648505420000000) Tuesday, February 22, 2022 2:22:22.000000 PM GMT-05:00¶
Both UUIDv1 and UUIDv6 utilize the same values in clk_seq_hi_res, clock_seq_low, and node. All of which have been generated with random data.¶
# Unix Nanosecond precision to Gregorian 100-nanosecond intervals gregorian_100_ns = (Unix_64_bit_nanoseconds / 100) + gregorian_Unix_offset # 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. # gregorian_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_nanoseconds = 0x16D6320C3D4DCC00 or 1645557742000000000 # Work: # gregorian_100_ns = (1645557742000000000 / 100) + 122192928000000000 # (138648505420000000 - 122192928000000000) * 100 = Unix_64_bit_nanoseconds # Final: # gregorian_100_ns = 0x1EC9414C232AB00 or 138648505420000000 # Original: 000111101100100101000001010011000010001100101010101100000000 # UUIDv1: 11000010001100101010101100000000|1001010000010100|0001|000111101100 # UUIDv6: 00011110110010010100000101001100|0010001100101010|0110|101100000000
---------------------------------------------- field bits value_hex ---------------------------------------------- time_low 32 0xC232AB00 time_mid 16 0x9414 time_hi_and_version 16 0x11EC clk_seq_hi_res 8 0xB3 clock_seq_low 8 0xC8 node 48 0x9E6BDECED846 ---------------------------------------------- total 128 ---------------------------------------------- final_hex: C232AB00-9414-11EC-B3C8-9E6BDECED846
----------------------------------------------- field bits value_hex ----------------------------------------------- time_high 32 0x1EC9414C time_mid 16 0x232A time_low_and_version 16 0x6B00 clk_seq_hi_res 8 0xB3 clock_seq_low 8 0xC8 node 48 0x9E6BDECED846 ----------------------------------------------- total 128 ----------------------------------------------- final_hex: 1EC9414C-232A-6B00-B3C8-9E6BDECED846
This example UUIDv7 test vector utilizes a well-known 32 bit Unix epoch with additional millisecond precision to fill the first 48 bits¶
rand_a and rand_b are filled with random data.¶
The timestamp is Tuesday, February 22, 2022 2:22:22.00 PM GMT-05:00 represented as 0x17F22E279B0 or 1645557742000¶
------------------------------- field bits value ------------------------------- unix_ts_ms 48 0x17F22E279B0 var 4 0x7 rand_a 12 0xCC3 var 2 b10 rand_b 62 0x18C4DC0C0C07398F ------------------------------- total 128 ------------------------------- final: 017F22E2-79B0-7CC3-98C4-DC0C0C07398F
This example UUIDv8 test vector utilizes a well-known 64 bit Unix epoch with nanosecond precision, truncated to the least-significant, right-most, bits to fill the first 48 bits through version.¶
The next two segments of custom_b and custom_c are are filled with random data.¶
Timestamp is Tuesday, February 22, 2022 2:22:22.000000 PM GMT-05:00 represented as 0x16D6320C3D4DCC00 or 1645557742000000000¶
It should be noted that this example is just to illustrate one scenario for UUIDv8. Test vectors will likely be implementation specific and vary greatly from this simple example.¶
------------------------------- field bits value ------------------------------- custom_a 48 0x320C3D4DCC00 ver 4 0x8 custom_b 12 0x75B var 2 b10 custom_c 62 0xEC932D5F69181C0 ------------------------------- total 128 ------------------------------- final: 320C3D4D-CC00-875B-8EC9-32D5F69181C0
| Msb0 | Msb1 | Msb2 | Msb3 | Version | Description |
| 0 | 0 | 0 | 0 | 0 | Unused |
| 0 | 0 | 0 | 1 | 1 | The Gregorian time-based UUID from in [RFC4122], Section 4.1.3 |
| 0 | 0 | 1 | 0 | 2 | DCE Security version, with embedded POSIX UIDs from [RFC4122], Section 4.1.3 |
| 0 | 0 | 1 | 1 | 3 | The name-based version specified in [RFC4122], Section 4.1.3 that uses MD5 hashing. |
| 0 | 1 | 0 | 0 | 4 | The randomly or pseudo-randomly generated version specified in [RFC4122], Section 4.1.3. |
| 0 | 1 | 0 | 1 | 5 | The name-based version specified in [RFC4122], Section 4.1.3 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. |
| Msb0 | Msb1 | Msb2 | Msb3 | Version | Description |
| 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 |
| Msb0 | Msb1 | Msb2 | Msb3 | Version | Description |
| 0 | 0 | 0 | 0 | 0 | Unused |
| 0 | 0 | 0 | 1 | 1 | The Gregorian time-based UUID from in |
| 0 | 0 | 1 | 0 | 2 | DCE Security version, with embedded POSIX UIDs from |
| 0 | 0 | 1 | 1 | 3 | The name-based version specified in |
| 0 | 1 | 0 | 0 | 4 | The randomly or pseudo-randomly generated version specified in |
| 0 | 1 | 0 | 1 | 5 | The name-based version specified in |
| 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. |
| Internet-Draft | new-uuid-format | June 2022 |
| Peabody & Davis | Expires 25 December 2022 | [Page] |
This document presents new Universally Unique Identifier (UUID) formats for use in modern applications and databases.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 25 December 2022.¶
Copyright (c) 2022 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) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
Many things have changed in the time since UUIDs were originally created. Modern applications have a need to create and utilize UUIDs as the primary identifier for a variety of different items in complex computational systems, including but not limited to database keys, file names, machine or system names, and identifiers for event-driven transactions.¶
One area UUIDs have gained popularity is as database keys. This stems from the increasingly distributed nature of modern applications. In such cases, "auto increment" schemes often used by databases do not work well, as the effort required to coordinate unique numeric identifiers across a network can easily become a burden. The fact that UUIDs can be used to create unique, reasonably short values in distributed systems without requiring synchronization makes them a good alternative, but UUID versions 1-5 lack certain other desirable characteristics:¶
Non-time-ordered UUID versions such as UUIDv4 have poor database index locality. Meaning new values created in succession are not close to each other in the index and thus require inserts to be performed at random locations. The negative performance effects of which on common structures used for this (B-tree and its variants) can be dramatic.¶
The 100-nanosecond, Gregorian epoch used in UUIDv1 timestamps is uncommon and difficult to represent accurately using a standard number format such as [IEEE754].¶
Introspection/parsing is required to order by time sequence; as opposed to being able to perform a simple byte-by-byte comparison.¶
Privacy and network security issues arise from using a MAC address in the node field of Version 1 UUIDs. Exposed MAC addresses can be used as an attack surface to locate machines and reveal various other information about such machines (minimally manufacturer, potentially other details). Additionally, with the advent of virtual machines and containers, MAC address uniqueness is no longer guaranteed.¶
Many of the implementation details specified in [RFC4122] involve trade offs that are neither possible to specify for all applications nor necessary to produce interoperable implementations.¶
[RFC4122] does not distinguish between the requirements for generation of a UUID versus an application which simply stores one, which are often different.¶
Due to the aforementioned issue, many widely distributed database applications and large application vendors have sought to solve the problem of creating a better time-based, sortable unique identifier for use as a database key. This has lead to numerous implementations over the past 10+ years solving the same problem in slightly different ways.¶
While preparing this specification the following 16 different implementations were analyzed for trends in total ID length, bit Layout, lexical formatting/encoding, timestamp type, timestamp format, timestamp accuracy, node format/components, collision handling and multi-timestamp tick generation sequencing.¶
[LexicalUUID] by Twitter¶
[ShardingID] by Instagram¶
[Elasticflake] by P. Pearcy¶
[orderedUuid] by IT. Cabrera¶
An inspection of these implementations and the issues described above has led to this document which attempts to adapt UUIDs to address these issues.¶
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.¶
The following UUIDs are hereby introduced:¶
RFC EDITOR PLEASE DELETE THIS SECTION.¶
draft-04¶
- Fixed bad title in IEEE754 Normative Reference¶
- Fixed bad GMT offset in Test Vector Appendix¶
- Removed MAY in Counters section¶
- Condensed Counter Type into Counter Methods to reduce text¶
- Removed option for random increment along with fixed-length counter¶
- Described how to handle scenario where New UUID less than Old UUID¶
- Allow timestamp increment if counter overflows¶
- Replaced UUIDv8 C code snippet with full generation example¶
- Fixed RFC4086 Reference link¶
- Describe reseeding best practice for CSPRNG¶
- Changed MUST to SHOULD removing requirement for absolute monotonicity¶
draft-03¶
- Reworked the draft body to make the content more concise¶
- UUIDv6 section reworked to just the reorder of the timestamp¶
- UUIDv7 changed to simplify timestamp mechanism to just millisecond Unix timestamp¶
- UUIDv8 relaxed to be custom in all elements except version and variant¶
- Introduced Max UUID.¶
- Added C code samples in Appendix.¶
- Added test vectors in Appendix.¶
- Version and Variant section combined into one section.¶
- Changed from pseudo-random number generators to cryptographically secure pseudo-random number generator (CSPRNG).¶
- Combined redundant topics from all UUIDs into sections such as Timestamp granularity, Monotonicity and Counters, Collision Resistance, Sorting, and Unguessability, etc.¶
- Split Encoding and Storage into Opacity and DBMS and Database Considerations¶
- Reworked Global Uniqueness under new section Global and Local Uniqueness¶
- Node verbiage only used in UUIDv6 all others reference random/rand instead¶
- Clock sequence verbiage changed simply to counter in any section other than UUIDv6¶
- Added Abbreviations section¶
- Updated IETF Draft XML Layout¶
- Added information about little-endian UUIDs¶
draft-02¶
- Added Changelog¶
- Fixed misc. grammatical errors¶
- Fixed section numbering issue¶
- Fixed some UUIDvX reference issues¶
- Changed all instances of "motonic" to "monotonic"¶
- Changed all instances of "#-bit" to "# bit"¶
- Changed "proceeding" verbiage to "after" in section 7¶
- Added details on how to pad 32 bit Unix timestamp to 36 bits in UUIDv7¶
- Added details on how to truncate 64 bit Unix timestamp to 36 bits in UUIDv7¶
- Added forward reference and bullet to UUIDv8 if truncating 64 bit Unix Epoch is not an option.¶
- Fixed bad reference to non-existent "time_or_node" in section 4.5.4¶
draft-01¶
- Complete rewrite of entire document.¶
- The format, flow and verbiage used in the specification has been reworked to mirror the original RFC 4122 and current IETF standards.¶
- Removed the topics of UUID length modification, alternate UUID text formats, and alternate UUID encoding techniques.¶
- Research into 16 different historical and current implementations of time-based universal identifiers was completed at the end of 2020 in attempt to identify trends which have directly influenced design decisions in this draft document (https://github.com/uuid6/uuid6-ietf-draft/tree/master/research)¶
- Prototype implementation have been completed for UUIDv6, UUIDv7, and UUIDv8 in various languages by many GitHub community members. (https://github.com/uuid6/prototypes)¶
The variant bits utilized by UUIDs in this specification remain in the same octet as originally defined by [RFC4122], Section 4.1.1.¶
The next table details Variant 10xx (8/9/A/B) and the new versions defined by this specification. A complete guide to all versions within this variant has been includes in Appendix C.1.¶
| Msb0 | Msb1 | Msb2 | Msb3 | Version | Description |
| 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 |
For UUID version 6, 7 and 8 the variant field placement from [RFC4122] are unchanged. An example version/variant layout for UUIDv6 follows the table where M is the version and N is the variant.¶
00000000-0000-6000-8000-000000000000 00000000-0000-6000-9000-000000000000 00000000-0000-6000-A000-000000000000 00000000-0000-6000-B000-000000000000 xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
The UUID format is 16 octets; the variant bits in conjunction with the version bits described in the next section in determine finer structure.¶
UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality. It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs. Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 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 [RFC4122], Section 4.1.4, 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 bits remain unchanged from their usage and position in [RFC4122], Section 4.1.5.¶
The 48 bit node SHOULD be set to a pseudo-random value however implementations MAY choose to retain the old MAC address behavior from [RFC4122], Section 4.1.6 and [RFC4122], Section 4.5. 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 1¶
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 | time_low_and_version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|clk_seq_hi_res | clk_seq_low | node (0-1) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| node (2-5) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
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.¶
UUID version 7 features a time-ordered value field derived from the widely implemented and well known Unix Epoch timestamp source, the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded. As well as improved entropy characteristics over versions 1 or 6.¶
Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 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 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
UUID version 8 provides an RFC-compatible format for experimental or vendor-specific use cases. The only requirement is that the variant and version bits MUST be set as defined in Section 4. UUIDv8's uniqueness will be implementation-specific and SHOULD NOT be assumed.¶
The only explicitly defined bits are the Version and Variant leaving 122 bits for implementation specific time-based UUIDs. To be clear: UUIDv8 is not a replacement for UUIDv4 where all 122 extra bits are filled with random data.¶
Some example situations in which UUIDv8 usage could occur:¶
An implementation would like to embed extra information within the UUID other than what is defined in this document.¶
An implementation has other application/language restrictions which inhibit the use of one of the current UUIDs.¶
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 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The Max UUID is 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 Nil UUID defined in [RFC4122], Section 4.1.7¶
FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF
The minimum requirements for generating UUIDs are described in this document for each version. Everything else is an implementation detail and up to the implementer to decide what is appropriate for a given implementation. That being said, various relevant factors are covered below to help guide an implementer through the different trade-offs among differing UUID implementations.¶
UUID timestamp source, precision and length was the topic of great debate while creating this specification. As such choosing the right timestamp for your application is a very important topic. This section will detail some of the most common points on this topic.¶
Monotonicity is the backbone of time-based sortable UUIDs. Naturally time-based UUIDs from this document will be monotonic due to an embedded timestamp however implementations can guarantee additional monotonicity via the concepts covered in this section.¶
Additionally, care SHOULD be taken to ensure UUIDs generated in batches are also monotonic. That is, if one-thousand UUIDs are generated for the same timestamp; there is sufficient logic for organizing the creation order of those one-thousand UUIDs. For batch UUID creation implementions MAY utilize a monotonic counter which SHOULD increment for each UUID created during a given timestamp.¶
For single-node UUID implementations that do not need to create batches of UUIDs, the embedded timestamp within UUID version 1, 6, and 7 can provide sufficient monotonicity guarantees by simply ensuring that timestamp increments before creating a new UUID. For the topic of Distributed Nodes please refer to Section 6.3¶
Implementations SHOULD choose one method for single-node UUID implementations that require batch UUID creation.¶
The following sub-topics cover topics related solely with creating reliable fixed-length dedicated counters:¶
The following sub-topics cover rollover handling with either type of counter method:¶
Implementations MAY use the following logic to ensure UUIDs featuring 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; re-initialize the desired counter method to the new timestamp and generate new random bytes (if the bytes were frozen or being used as the seed for a monotonic counter).¶
Implementations SHOULD check if the the currently generated UUID is greater than the previously generated UUID. If this is not the case then any number of things could have occurred. Such as, but not limited to, clock rollbacks, leap second handling or counter rollovers. Applications SHOULD embed sufficient logic to catch these scenarios and correct the problem ensuring the next UUID generated is greater than the previous. To handle this scenario, the general guidance is that application MAY reuse the previous timestamp and increment the previous counter method.¶
Implementations SHOULD weigh the consequences of UUID collisions within their application and when deciding between UUID versions that use entropy (random) versus the other components such as Section 6.1 and Section 6.2. This is especially true for distributed node collision resistance as defined by Section 6.3.¶
There are two example scenarios below which help illustrate the varying seriousness of a collision within an application.¶
UUIDs created by this specification MAY be used to provide local uniqueness guarantees. For example, ensuring UUIDs created within a local application context are unique within a database MAY be sufficient for some implementations where global uniqueness outside of the application context, in other applications, or around the world is not required.¶
Although true global uniqueness is impossible to guarantee without a shared knowledge scheme; a shared knowledge scheme is not required by UUID to provide uniqueness guarantees. Implementations MAY implement a shared knowledge scheme introduced in Section 6.3 as they see fit to extend the uniqueness guaranteed this specification and [RFC4122].¶
Implementations SHOULD utilize a cryptographically secure pseudo-random number generator (CSPRNG) to provide values that are both difficult to predict ("unguessable") and have a low likelihood of collision ("unique"). Care SHOULD be taken to ensure the CSPRNG state is properly reseeded upon state changes, such as process forks, to ensure proper CSPRNG operation. CSPRNG ensures the best of Section 6.4 and Section 8 are present in modern UUIDs.¶
Advice on generating cryptographic-quality random numbers can be found in [RFC4086]¶
UUIDv6 and UUIDv7 are designed so that implementations that require sorting (e.g. database indexes) SHOULD sort as opaque raw bytes, without need for parsing or introspection.¶
Time ordered monotonic UUIDs benefit from greater database index locality because the new values are near each other in the index. As a result objects are more easily clustered together for better performance. The real-world differences in this approach of index locality vs random data inserts can be quite large.¶
UUIDs formats created by this specification SHOULD be Lexicographically sortable while in the textual representation.¶
UUIDs created by this specification are crafted with big-ending byte order (network byte order) in mind. If Little-endian style is required a custom UUID format SHOULD be created using UUIDv8.¶
UUIDs SHOULD be treated as opaque values and implementations SHOULD NOT examine the bits in a UUID to whatever extent is possible. However, where necessary, inspectors should refer to Section 4 for more information on determining UUID version and variant.¶
For many applications, such as databases, storing UUIDs as text is unnecessarily verbose, requiring 288 bits to represent 128 bit UUID values. Thus, where feasible, UUIDs SHOULD be stored within database applications as the underlying 128 bit binary value.¶
For other systems, UUIDs MAY be stored in binary form or as text, as appropriate. The trade-offs to both approaches are as such:¶
Storing as binary requires less space and may result in faster data access.¶
Storing as text requires more space but may require less translation if the resulting text form is to be used after retrieval and thus maybe simpler to implement.¶
DBMS vendors are encouraged to provide functionality to generate and store UUID formats defined by this specification for use as identifiers or left parts of identifiers such as, but not limited to, primary keys, surrogate keys for temporal databases, foreign keys included in polymorphic relationships, and keys for key-value pairs in JSON columns and key-value databases. Applications using a monolithic database may find using database-generated UUIDs (as opposed to client-generate UUIDs) provides the best UUID monotonicity. In addition to UUIDs, additional identifiers MAY be used to ensure integrity and feedback.¶
This document has no IANA actions.¶
MAC addresses pose inherent security risks and SHOULD not be used within a UUID. Instead CSPRNG data SHOULD be selected from a source with sufficient entropy to ensure guaranteed uniqueness among UUID generation. See Section 6.6 for more information.¶
Timestamps embedded in the UUID do pose a very small attack surface. The timestamp in conjunction with an embedded counter does signal the order of creation for a given UUID and it's corresponding data but does not define anything about the data itself or the application as a whole. If UUIDs are required for use with any security operation within an application context in any shape or form then [RFC4122] UUIDv4 SHOULD be utilized.¶
The authors gratefully acknowledge the contributions of 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, sergeyprokhorenko, LiosK As well as all of those in the IETF community and on GitHub to who contributed to the discussions which resulted in this document.¶
This section details a function in C which converts from a UUID version 1 to version 6:¶
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <arpa/inet.h>
#include <uuid/uuid.h>
/* Converts UUID version 1 to version 6 in place. */
void uuidv1tov6(uuid_t u) {
uint64_t ut;
unsigned char *up = (unsigned char *)u;
// load ut with the first 64 bits of the UUID
ut = ((uint64_t)ntohl(*((uint32_t*)up))) << 32;
ut |= ((uint64_t)ntohl(*((uint32_t*)&up[4])));
// dance the bit-shift...
ut =
((ut >> 32) & 0x0FFF) | // 12 least significant bits
(0x6000) | // version number
((ut >> 28) & 0x0000000FFFFF0000) | // next 20 bits
((ut << 20) & 0x000FFFF000000000) | // next 16 bits
(ut << 52); // 12 most significant bits
// store back in UUID
*((uint32_t*)up) = htonl((uint32_t)(ut >> 32));
*((uint32_t*)&up[4]) = htonl((uint32_t)(ut));
}
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
// ...
// csprng data source
FILE *rndf;
rndf = fopen("/dev/urandom", "r");
if (rndf == 0) {
printf("fopen /dev/urandom error\n");
return 1;
}
// ...
// generate one UUIDv7E
uint8_t u[16];
struct timespec ts;
int ret;
ret = clock_gettime(CLOCK_REALTIME, &ts);
if (ret != 0) {
printf("clock_gettime error: %d\n", ret);
return 1;
}
uint64_t tms;
tms = ((uint64_t)ts.tv_sec) * 1000;
tms += ((uint64_t)ts.tv_nsec) / 1000000;
memset(u, 0, 16);
fread(&u[6], 10, 1, rndf); // fill everything after the timestamp with random bytes
*((uint64_t*)(u)) |= htonll(tms << 16); // shift time into first 48 bits and OR into place
u[8] = 0x80 | (u[8] & 0x3F); // set variant field, top two bits are 1, 0
u[6] = 0x70 | (u[6] & 0x0F); // set version field, top four bits are 0, 1, 1, 1
UUIDv8 will vary greatly from implementation to implementation.¶
The following example utilizes:¶
32 bit custom-epoch timestamp (seconds elapsed since 2020-01-01 00:00:00 UTC)¶
16 bit exotic resolution (~15 microsecond) subsecond timestamp encoded using the fractional representation¶
58 bit random number¶
8 bit application-specific unique node ID¶
8 bit rolling sequence number¶
#include <stdint.h>
#include <time.h>
int get_random_bytes(uint8_t *buffer, int count) {
// ...
}
int generate_uuidv8(uint8_t *uuid, uint8_t node_id) {
struct timespec tp;
if (clock_gettime(CLOCK_REALTIME, &tp) != 0)
return -1; // real-time clock error
// 32 bit biased timestamp (seconds elapsed since 2020-01-01 00:00:00 UTC)
uint32_t timestamp_sec = tp.tv_sec - 1577836800;
uuid[0] = timestamp_sec >> 24;
uuid[1] = timestamp_sec >> 16;
uuid[2] = timestamp_sec >> 8;
uuid[3] = timestamp_sec;
// 16 bit subsecond fraction (~15 microsecond resolution)
uint16_t timestamp_subsec = ((uint64_t)tp.tv_nsec << 16) / 1000000000;
uuid[4] = timestamp_subsec >> 8;
uuid[5] = timestamp_subsec;
// 58 bit random number and required ver and var fields
if (get_random_bytes(&uuid[6], 8) != 0)
return -1; // random number generator error
uuid[6] = 0x80 | (uuid[6] & 0x0f);
uuid[8] = 0x80 | (uuid[8] & 0x3f);
// 8 bit application-specific node ID to guarantee application-wide uniqueness
uuid[14] = node_id;
// 8 bit rolling sequence number to help ensure process-wide uniqueness
static uint8_t sequence = 0;
uuid[15] = sequence++; // NOTE: unprotected from race conditions
return 0;
}
Both UUIDv1 and UUIDv6 test vectors utilize the same 60 bit timestamp: 0x1EC9414C232AB00 (138648505420000000) Tuesday, February 22, 2022 2:22:22.000000 PM GMT-05:00¶
Both UUIDv1 and UUIDv6 utilize the same values in clk_seq_hi_res, clock_seq_low, and node. All of which have been generated with random data.¶
# Unix Nanosecond precision to Gregorian 100-nanosecond intervals gregorian_100_ns = (Unix_64_bit_nanoseconds / 100) + gregorian_Unix_offset # 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. # gregorian_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_nanoseconds = 0x16D6320C3D4DCC00 or 1645557742000000000 # Work: # gregorian_100_ns = (1645557742000000000 / 100) + 122192928000000000 # (138648505420000000 - 122192928000000000) * 100 = Unix_64_bit_nanoseconds # Final: # gregorian_100_ns = 0x1EC9414C232AB00 or 138648505420000000 # Original: 000111101100100101000001010011000010001100101010101100000000 # UUIDv1: 11000010001100101010101100000000|1001010000010100|0001|000111101100 # UUIDv6: 00011110110010010100000101001100|0010001100101010|0110|101100000000
---------------------------------------------- field bits value_hex ---------------------------------------------- time_low 32 0xC232AB00 time_mid 16 0x9414 time_hi_and_version 16 0x11EC clk_seq_hi_res 8 0xB3 clock_seq_low 8 0xC8 node 48 0x9E6BDECED846 ---------------------------------------------- total 128 ---------------------------------------------- final_hex: C232AB00-9414-11EC-B3C8-9E6BDECED846
----------------------------------------------- field bits value_hex ----------------------------------------------- time_high 32 0x1EC9414C time_mid 16 0x232A time_low_and_version 16 0x6B00 clk_seq_hi_res 8 0xB3 clock_seq_low 8 0xC8 node 48 0x9E6BDECED846 ----------------------------------------------- total 128 ----------------------------------------------- final_hex: 1EC9414C-232A-6B00-B3C8-9E6BDECED846
This example UUIDv7 test vector utilizes a well-known 32 bit Unix epoch with additional millisecond precision to fill the first 48 bits¶
rand_a and rand_b are filled with random data.¶
The timestamp is Tuesday, February 22, 2022 2:22:22.00 PM GMT-05:00 represented as 0x17F22E279B0 or 1645557742000¶
------------------------------- field bits value ------------------------------- unix_ts_ms 48 0x17F22E279B0 var 4 0x7 rand_a 12 0xCC3 var 2 b10 rand_b 62 0x18C4DC0C0C07398F ------------------------------- total 128 ------------------------------- final: 017F22E2-79B0-7CC3-98C4-DC0C0C07398F
This example UUIDv8 test vector utilizes a well-known 64 bit Unix epoch with nanosecond precision, truncated to the least-significant, right-most, bits to fill the first 48 bits through version.¶
The next two segments of custom_b and custom_c are are filled with random data.¶
Timestamp is Tuesday, February 22, 2022 2:22:22.000000 PM GMT-05:00 represented as 0x16D6320C3D4DCC00 or 1645557742000000000¶
It should be noted that this example is just to illustrate one scenario for UUIDv8. Test vectors will likely be implementation specific and vary greatly from this simple example.¶
------------------------------- field bits value ------------------------------- custom_a 48 0x320C3D4DCC00 ver 4 0x8 custom_b 12 0x75B var 2 b10 custom_c 62 0xEC932D5F69181C0 ------------------------------- total 128 ------------------------------- final: 320C3D4D-CC00-875B-8EC9-32D5F69181C0
| Msb0 | Msb1 | Msb2 | Msb3 | Version | Description |
| 0 | 0 | 0 | 0 | 0 | Unused |
| 0 | 0 | 0 | 1 | 1 | The Gregorian time-based UUID from in [RFC4122], Section 4.1.3 |
| 0 | 0 | 1 | 0 | 2 | DCE Security version, with embedded POSIX UIDs from [RFC4122], Section 4.1.3 |
| 0 | 0 | 1 | 1 | 3 | The name-based version specified in [RFC4122], Section 4.1.3 that uses MD5 hashing. |
| 0 | 1 | 0 | 0 | 4 | The randomly or pseudo-randomly generated version specified in [RFC4122], Section 4.1.3. |
| 0 | 1 | 0 | 1 | 5 | The name-based version specified in [RFC4122], Section 4.1.3 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. |
| Internet-Draft | new-uuid-format | April 2021 |
| Peabody & Davis | Expires 28 October 2021 | [Page] |
This document presents new time-based UUID formats which are suited for use as a database key.¶
A common case for modern applications is to create a unique identifier for use as a primary key in a database table. This identifier usually implements an embedded timestamp that is sortable using the monotonic creation time in the most significant bits. In addition the identifier is highly collision resistant, difficult to guess, and provides minimal security attack surfaces. None of the existing UUID versions, including UUIDv1, fulfill each of these requirements in the most efficient possible way. This document is a proposal to update [RFC4122] with three new UUID versions that address these concerns, each with different trade-offs.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 28 October 2021.¶
Copyright (c) 2021 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) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119].¶
A lot of things have changed in the time since UUIDs were originally created. Modern applications have a need to use (and many have already implemented) UUIDs as database primary keys.¶
The motivation for using UUIDs as database keys stems primarily from the fact that applications are increasingly distributed in nature. Simplistic "auto increment" schemes with integers in sequence do not work well in a distributed system since the effort required to synchronize such numbers across a network can easily become a burden. The fact that UUIDs can be used to create unique and reasonably short values in distributed systems without requiring synchronization makes them a good candidate for use as a database key in such environments.¶
However some properties of [RFC4122] UUIDs are not well suited to this task. First, most of the existing UUID versions such as UUIDv4 have poor database index locality. Meaning new values created in succession are not close to each other in the index and thus require inserts to be performed at random locations. The negative performance effects of which on common structures used for this (B-tree and its variants) can be dramatic. As such newly inserted values SHOULD be time-ordered to address this.¶
While it is true that UUIDv1 does contain an embedded timestamp and can be time-ordered; UUIDv1 has other issues. It is possible to sort Version 1 UUIDs by time but it is a laborious task. The process requires breaking the bytes of the UUID into various pieces, re-ordering the bits, and then determining the order from the reconstructed timestamp. This is not efficient in very large systems. Implementations would be simplified with a sort order where the UUID can simply be treated as an opaque sequence of bytes and ordered as such.¶
After the embedded timestamp, the remaining 64 bits are in essence used to provide uniqueness both on a global scale and within a given timestamp tick. The clock sequence value ensures that when multiple UUIDs are generated for the same timestamp value are given a monotonic sequence value. This explicit sequencing helps further facilitate sorting. The remaining random bits ensure collisions are minimal.¶
Furthermore, UUIDv1 utilizes a non-standard timestamp epoch derived from the Gregorian Calendar. More specifically, the Coordinated Universal Time (UTC) as a count of 100-nanosecond intervals since 00:00:00.00, 15 October 1582. Implementations and many languages may find it easier to implement the widely adopted and well known Unix Epoch, a custom epoch, or another timestamp source with various levels of timestamp precision required by the application.¶
Lastly, privacy and network security issues arise from using a MAC address in the node field of Version 1 UUIDs. Exposed MAC addresses can be used as an attack surface to locate machines and reveal various other information about such machines (minimally manufacturer, potentially other details). Instead "cryptographically secure" pseudo-random number generators (CSPRNGs) or pseudo-random number generators (PRNG) SHOULD be used within an application context to provide uniqueness and unguessability.¶
Due to the shortcomings of UUIDv1 and UUIDv4 details so far, many widely distributed database applications and large application vendors have sought to solve the problem of creating a better time-based, sortable unique identifier for use as a database key. This has lead to numerous implementations over the past 10+ years solving the same problem in slightly different ways.¶
While preparing this specification the following 16 different implementations were analyzed for trends in total ID length, bit Layout, lexical formatting/encoding, timestamp type, timestamp format, timestamp accuracy, node format/components, collision handling and multi-timestamp tick generation sequencing.¶
[LexicalUUID] by Twitter¶
[ShardingID] by Instagram¶
[Elasticflake] by P. Pearcy¶
[orderedUuid] by IT. Cabrera¶
An inspection of these implementations details the following trends that help define this standard:¶
- Timestamps MUST be k-sortable. That is, values within or close to the same timestamp are ordered properly by sorting algorithms.¶
- Timestamps SHOULD be big-endian with the most-significant bits of the time embedded as-is without reordering.¶
- Timestamps SHOULD utilize millisecond precision and Unix Epoch as timestamp source. Although, there is some variation to this among implementations depending on the application requirements.¶
- The ID format SHOULD be Lexicographically sortable while in the textual representation.¶
- IDs MUST ensure proper embedded sequencing to facilitate sorting when multiple UUIDs are created during a given timestamp.¶
- IDs MUST NOT require unique network identifiers as part of achieving uniqueness.¶
- Distributed nodes MUST be able to create collision resistant Unique IDs without a consulting a centralized resource.¶
In order to solve these challenges this specification introduces three new version identifiers assigned for time-based UUIDs.¶
The first, UUIDv6, aims to be the easiest to implement for applications which already implement UUIDv1. The UUIDv6 specification keeps the original Gregorian timestamp source but does not reorder the timestamp bits as per the process utilized by UUIDv1. UUIDv6 also requires that pseudo-random data MUST be used in place of the MAC address. The rest of the UUIDv1 format remains unchanged in UUIDv6. See Section 4.3¶
Next, UUIDv7 introduces an entirely new time-based UUID bit layout utilizing a variable length timestamp sourced from the widely implemented and well known Unix Epoch timestamp source. The timestamp is broken into a 36-bit integer sections part, and is followed by a field of variable length which represents the sub-second timestamp portion, encoded so that each bit from most to least significant adds more precision. See Section 4.4¶
Finally, UUIDv8 introduces a relaxed time-based UUID format that caters to application implementations that cannot utilize UUIDv1, UUIDv6, or UUIDv7. UUIDv8 also future-proofs this specification by allowing time-based UUID formats from timestamp sources that are not yet be defined. The variable size timestamp offers lots of flexibility to create an implementation specific RFC compliant time-based UUID while retaining the properties that make UUID great. See Section 4.5¶
The UUID length of 16 octets (128 bits) remains unchanged. The textual representation of a UUID consisting of 36 hexadecimal and dash characters in the format 8-4-4-4-12 remains unchanged for human readability. In addition the position of both the Version and Variant bits remain unchanged in the layout.¶
Table 1 defines the 4-bit version found in Bits 48 through 51 within a given UUID.¶
| Msb0 | Msb1 | Msb2 | Msb3 | Version | Description |
| 0 | 1 | 1 | 0 | 6 | Reordered Gregorian time-based UUID |
| 0 | 1 | 1 | 1 | 7 | Variable length Unix Epoch time-based UUID |
| 1 | 0 | 0 | 0 | 8 | Custom time-based UUID |
The variant bits utilized by UUIDs in this specification remains the same as [RFC4122], Section 4.1.1.¶
The Table 2 lists the contents of the variant field, bits 64 and 65, where the letter "x" indicates a "don't-care" value. Common hex values of 8 (1000), 9 (1001), A (1010), and B (1011) frequent the text representation.¶
| Msb0 | Msb1 | Msb2 | Description |
| 1 | 0 | x | The variant specified in this document. |
UUIDv6 aims to be the easiest to implement by reusing most of the layout of bits found in UUIDv1 but with changes to bit ordering for the timestamp. Where UUIDv1 splits the timestamp bits into three distinct parts and orders them as time_low, time_mid, time_high_and_version. UUIDv6 instead keeps the source bits from the timestamp intact and changes the order to time_high, time_mid, and time_low. Incidentally this will match the original 60-bit Gregorian timestamp source. The clock sequence bits remain unchanged from their usage and position in [RFC4122]. The 48-bit node MUST be set to a pseudo-random value.¶
The format for the 16-octet, 128-bit UUIDv6 is shown in Figure 1¶
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 | time_low_and_version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|clk_seq_hi_res | clk_seq_low | node (0-1) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| node (2-5) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
UUIDv6 reuses the 60-bit Gregorian timestamp with 100-nanosecond precision defined in [RFC4122], Section 4.1.4.¶
UUIDv6 makes no change to the Clock Sequence usage defined by [RFC4122], Section 4.1.5.¶
UUIDv6 node bits SHOULD be set to a 48-bit random or pseudo-random number. UUIDv6 nodes SHOULD NOT utilize an IEEE 802 MAC address or the [RFC4122], Section 4.5 method of generating a random multicast IEEE 802 MAC address.¶
The following implementation algorithm is based on [RFC4122] but with changes specific to UUIDv6:¶
From a system-wide shared stable store (e.g., a file) or global variable, read the UUID generator state: the values of the timestamp and clock sequence used to generate the last UUID.¶
Obtain the current time as a 60-bit count of 100-nanosecond intervals since 00:00:00.00, 15 October 1582.¶
Set the time_low field to the 12 least significant bits of the starting 60-bit timestamp.¶
Truncate the timestamp to the 48 most significant bits in order to create time_high_and_time_mid.¶
Set the time_high field to the 32 most significant bits of the truncated timestamp.¶
Set the time_mid field to the 16 least significant bits of the truncated timestamp.¶
Create the 16-bit time_low_and_version by concatenating the 4-bit UUIDv6 version with the 12-bit time_low.¶
If the state was unavailable (e.g., non-existent or corrupted) or the timestamp is greater than the current timestamp generate a random 14-bit clock sequence value.¶
If the state was available, but the saved timestamp is less than or equal to the current timestamp, increment the clock sequence value.¶
Complete the 16-bit clock sequence high, low and reserved creation by concatenating the clock sequence onto UUID variant bits which take the most significant position in the 16-bit value.¶
Generate a 48-bit psuedo-random node.¶
Format by concatenating the 128 bits from each parts: time_high|time_mid|time_low_and_version|variant_clk_seq|node¶
Save the state (current timestamp and clock sequence) back to the stable store¶
The steps for splitting time_high_and_time_mid into time_high and time_mid are optional since the 48-bits of time_high and time_mid will remain in the same order as time_high_and_time_mid during the final concatenation. This extra step of splitting into the most significant 32 bits and least significant 16 bits proves useful when reusing an existing UUIDv1 implementation. In which the following logic can be applied to reshuffle the bits with minimal modifications.¶
| UUIDv1 Field | Bits | UUIDv6 Field |
| time_low | 32 | time_high |
| time_mid | 16 | time_mid |
| time_high | 12 | time_low |
The UUIDv7 format is designed to encode a Unix timestamp with arbitrary sub-second precision. The key property provided by UUIDv7 is that timestamp values generated by one system and parsed by another are guaranteed to have sub-section precision of either the generator or the parser, whichever is less. Additionally, the system parsing the UUIDv7 value does not need to know which precision was used during encoding in order to function correctly.¶
The format for the 16-octet, 128-bit UUIDv6 is shown in Figure 2¶
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unixts |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|unixts | subsec_a | ver | subsec_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| subsec_seq_node |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| subsec_seq_node |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
UUIDv7 utilizes a 36-bit big-endian unsigned Unix Timestamp value (number of seconds since the epoch of 1 Jan 1970, leap seconds excluded so each hour is exactly 3600 seconds long).¶
Additional sub-second precision (millisecond, nanosecond, microsecond, etc) MAY be provided for encoding and decoding in the remaining bits in the layout.¶
UUIDv7 SHOULD utilize a motonic sequence counter to provide additional sequencing guarantees when multiple UUIDv7 values are created in the same UNIXTS and SUBSEC timestamp. The amount of bits allocates to the sequence counter depend on the precision of the timestamp. For example, a more accurate timestamp source using nanosecond precision will require less clock sequence bits than a timestamp source utilizing seconds for precision. For best sequencing results the sequence counter SHOULD be placed immediately after available sub-second bits.¶
The clock sequence MUST start at zero and increment monotonically for each new UUID created on by the application on the same timestamp. When the timestamp increments the clock sequence MUST be reset to zero. The clock sequence MUST NOT rollover or reset to zero unless the timestamp has incremented. Care MUST be given to ensure that an adequate sized clock sequence is selected for a given application based on expected timestamp precision and expected UUID generation rates.¶
UUIDv7 implementations, even with very detailed sub-second precision and the optional sequence counter, MAY have leftover bits that will be identified as the Node for this section. The UUIDv7 Node MAY contain any set of data an implementation desires however the node MUST NOT be set to all 0s which does not ensure global uniqueness. In most scenarios the node SHOULD be filled with pseudo-random data.¶
The UUIDv7 bit layout for encoding and decoding are described separately in this document.¶
Since the UUIDv7 Unix timestamp is fixed at 36 bits in length the exact layout for encoding UUIDv7 depends on the precision (number of bits) used for the sub-second portion and the sizes of the optionally desired sequence counter and node bits.¶
Three examples of UUIDv7 encoding are given below as a general guidelines but implementations are not limited to just these three examples.¶
All of these fields are only used during encoding, and during decoding the system is unaware of the bit layout used for them and considers this information opaque. As such, implementations generating these values can assign whatever lengths to each field it deems applicable, as long as it does not break decoding compatibility (i.e. Unix timestamp (unixts), version (ver) and variant (var) have to stay where they are, and clock sequence counter (seq), random (random) or other implementation specific values must follow the sub-second encoding).¶
In Figure 3 the UUIDv7 has been created with millisecond precision with the available sub-second precision bits.¶
Examining Figure 3 one can observe:¶
The first 36 bits have been dedicated to the Unix Timestamp (unixts)¶
All 12 bits of scenario subsec_a is fully dedicated to millisecond information (msec).¶
The 4 Version bits remain unchanged (ver).¶
All 12 bits of subsec_b have been dedicated to a motonic clock sequence counter (seq).¶
The 2 Variant bits remain unchanged (var).¶
Finally the remaining 62 bits in the subsec_seq_node section are layout is filled out with random data to pad the length and provide guaranteed uniqueness (rand).¶
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unixts |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|unixts | msec | ver | seq |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| rand |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rand |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
In Figure 4 the UUIDv7 has been created with Microsecond precision with the available sub-second precision bits.¶
Examining Figure 4 one can observe:¶
The first 36 bits have been dedicated to the Unix Timestamp (unixts)¶
All 12 bits of scenario subsec_a is fully dedicated to providing sub-second encoding for the Microsecond precision (usec).¶
The 4 Version bits remain unchanged (ver).¶
All 12 bits of subsec_b have been dedicated to providing sub-second encoding for the Microsecond precision (usec).¶
The 2 Variant bits remain unchanged (var).¶
A 14 bit motonic clock sequence counter (seq) has been embedded in the most significant position of subsec_seq_node¶
Finally the remaining 48 bits in the subsec_seq_node section are layout is filled out with random data to pad the length and provide guaranteed uniqueness (rand).¶
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unixts |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|unixts | usec | ver | usec |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| seq | rand |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rand |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
In Figure 5 the UUIDv7 has been created with Nanosecond precision with the available sub-second precision bits.¶
Examining Figure 5 one can observe:¶
The first 36 bits have been dedicated to the Unix Timestamp (unixts)¶
All 12 bits of scenario subsec_a is fully dedicated to providing sub-second encoding for the Nanosecond precision (nsec).¶
The 4 Version bits remain unchanged (ver).¶
All 12 bits of subsec_b have been dedicated to providing sub-second encoding for the Nanosecond precision (nsec).¶
The 2 Variant bits remain unchanged (var).¶
The first 14 bit of the subsec_seq_node dedicated to providing sub-second encoding for the Nanosecond precision (nsec).¶
The next 8 bits of subsec_seq_node dedicated a motonic clock sequence counter (seq).¶
Finally the remaining 40 bits in the subsec_seq_node section are layout is filled out with random data to pad the length and provide guaranteed uniqueness (rand).¶
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unixts |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|unixts | nsec | ver | nsec |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| nsec | seq | rand |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rand |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
When decoding or parsing a UUIDv7 value there are only two values to be considered:¶
The unix timestamp defined as unixts¶
The sub-second precision values defined as subsec_a, subsec_b, and subsec_seq_node¶
As detailed in Figure 2 the unix timestamp (unixts) is always the first 36 bits of the UUIDv7 layout.¶
Similarly as per Figure 2, the sub-second precision values lie within subsec_a, subsec_b, and subsec_seq_node which are all interpreted as sub-second information after skipping over the version (ver) and (var) bits. These concatenated sub-second information bits are interpreted in a way where most to least significant bits represent a further division by two. This is the same normal place notation used to express fractional numbers, except in binary. For example, in decimal ".1" means one tenth, and ".01" means one hundredth. In this subsec field, a 1 means one half, 01 means one quarter, 001 is one eighth, etc. This scheme can work for any number of bits up to the maximum available, and keeps the most significant data leftmost in the bit sequence.¶
To perform the sub-second math, simply take the first (most significant/leftmost) N bits of subsec and divide it by 2^N. Take for example:¶
To parse the first 16 bits, extract that value as an integer and divide it by 65536 (2 to the 16th).¶
If these 16 bits are 0101 0101 0101 0101, then treating that as an integer gives 0x5555 or 21845 in decimal, and dividing by 65536 gives 0.3333282¶
This sub-second encoding scheme provides maximum interoperability across systems where different levels of time precision are required/feasible/available. The timestamp value derived from a UUIDv7 value SHOULD be "as close to the correct value as possible" when parsed, even across disparate systems.¶
Take for example the starting point for our next two UUIDv7 parsing scenarios:¶
Scenario 1:¶
Scenario 2:¶
UUIDv8 offers variable-size timestamp, clock sequence, and node values which allow for a highly customizable UUID that fits a given application needs.¶
UUIDv8 SHOULD only be utilized if an implementation cannot utilize UUIDv1, UUIDv6, or UUIDv8. Some situations in which UUIDv8 usage could occur:¶
An implementation would like to utilize a timestamp source not defined by the current time-based UUIDs.¶
An implementation would like to utilize a timestamp bit layout not defined by the current time-based UUIDs.¶
An implementation would like a specific level of precision within the timestamp not offered by current time-based UUIDs.¶
An implementation would like to embed extra information within the UUID node other than what is defined in this document.¶
An implementation has other application/language restrictions which inhibit the usage of one of the current time-based UUIDs.¶
Roughly speaking a properly formatted UUIDv8 SHOULD contain the following sections adding up to a total of 128-bits.¶
- Timestamp Bits (Variable Length)¶
- Clock Sequence Bits (Variable Length)¶
- Node Bits (Variable Length)¶
- UUIDv8 Version Bits (4 bits)¶
- UUID Variant Bits (2 Bits)¶
The only explicitly defined bits are the Version and Variant leaving 122 bits for implementation specific time-based UUIDs. To be clear: UUIDv8 is not a replacement for UUIDv4 where all 122 extra bits are filled with random data. UUIDv8's 128 bits (including the version and variant) SHOULD contain at the minimum a timestamp of some format in the most significant bit position followed directly by a clock sequence counter and finally a node containing either random data or implementation specific data.¶
A sample format in Figure 6 is used to further illustrate the point for the 16-octet, 128-bit UUIDv8.¶
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp_32 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp_48 | ver | time_or_seq |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| seq_or_node | node |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| node |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
UUIDv8's usage of timestamp relaxes both the timestamp source and timestamp length. Implementations are free to utilize any monotonically stable timestamp source for UUIDv8.¶
Some examples include:¶
The relaxed nature UUIDv8 timestamps also works to future proof this specification and allow implementations a method to create compliant time-based UUIDs using timestamp source that might not yet be defined.¶
Timestamps come in many sizes and UUIDv8 defines three fields that can easily used for the majority of timestamp lengths:¶
32-bit timestamp: using timestamp_32 and setting timestamp_48 to 0s¶
48-bit timestamp: using timestamp_32 and timestamp_48 entirely¶
60-bit timestamp: using timestamp_32, timestamp_48, and time_or_seq¶
64-bit timestamp: using timestamp_32, timestamp_48, and time_or_seq and truncating the timestamp the 60 most significant bits.¶
Although it is possible to create a timestamp larger than 64-bits in size The usage and bit layout of that timestamp format is up to the implementation. When a timestamp exceeds the 64th bit (octet 7), extra care must be taken to ensure the Variant bits are properly inserted at their respective location in the UUID. Likewise, the Version MUST always be implemented at the appropriate location.¶
Any timestamps that does not entirely fill the timestamp_32, timestamp_48 or time_or_seq MUST set all leftover bits in the least significant position of the respective field to 0. For example a 36-bit timestamp source would fully utilize timestamp_32 and 4-bits of timestamp_48. The remaining 12-bits in timestamp_48 MUST be set to 0.¶
By using implementation-specific timestamp sources it is not guaranteed that devices outside of the application context are able to extract and parse the timestamp from UUIDv8 without some pre-existing knowledge of the source timestamp used by the UUIDv8 implementation.¶
A clock sequence MUST be used with UUIDv8 as added sequencing guarantees when multiple UUIDv8 will be created on the same clock tick. The amount of bits allocated to the clock sequence depends on the precision of the timestamp source. For example, a more accurate timestamp source using nanosecond precision will require less clock sequence bits than a timestamp source utilizing seconds for precision.¶
The UUIDv8 layout in Figure 6 generically defines two possible clock sequence values that can leveraged:¶
12-bit clock sequence using time_or_seq for use when the timestamp is less than 48-bits which allows for 4095 UUIDs per clock tick.¶
8-bit clock sequence using seq_or_node when the timestamp uses more than 48-bits which allows for 255 UUIDs per clock tick.¶
An implementation MAY use both time_or_seq and seq_or_node for clock sequencing however it is highly unlikely that 20-bits of clock sequence are needed for a given clock tick. Furthermore, more bits from the node MAY be used for clock sequencing in the event that 8-bits is not sufficient.¶
The clock sequence MUST start at zero and increment monotonically for each new UUID created on by the application on the same timestamp. When the timestamp increments the clock sequence MUST be reset to zero. The clock sequence MUST NOT rollover or reset to zero unless the timestamp has incremented. Care MUST be given to ensure that an adequate sized clock sequence is selected for a given application based on expected timestamp precision and expected UUID generation rates.¶
The UUIDv8 Node MAY contain any set of data an implementation desires however the node MUST NOT be set to all 0s which does not ensure global uniqueness. In most scenarios the node will be filled with pseudo-random data.¶
The UUIDv8 layout in Figure 6 defines 2 sizes of Node depending on the timestamp size:¶
62-bit node encompassing seq_or_node and node Used when a timestamp of 48-bits or less is leveraged.¶
54-bit node when all 60-bits of the timestamp are in use and the seq_or_node is used as clock sequencing.¶
An implementation MAY choose to allocate bits from the node to the timestamp, clock sequence or application-specific embedded field. It is recommended that implementation utilize a node of at least 48-bits to ensure global uniqueness can be guaranteed.¶
The entire usage of UUIDv8 is meant to be variable and allow as much customization as possible to meet specific application/language requirements. As such any UUIDv8 implementations will likely vary among applications.¶
The following algorithm is a generic implementation using Figure 6 and the recommendations outlined in this specification.¶
32-bit timestamp, 12-bit sequence counter, 62-bit node:¶
From a system-wide shared stable store (e.g., a file) or global variable, read the UUID generator state: the values of the timestamp and clock sequence used to generate the last UUID.¶
Obtain the current time from the selected clock source as 32 bits.¶
Set the 32-bit field timestamp_32 to the 32 bits from the timestamp¶
Set 16-bit timestamp_48 to all 0s¶
Set the version to 8 (1000)¶
If the state was unavailable (e.g., non-existent or corrupted) or the timestamp is greater than the current timestamp; set the 12-bit clock sequence value (time_or_node) to 0¶
If the state was available, but the saved timestamp is less than or equal to the current timestamp, increment the clock sequence value (time_or_node).¶
Set the variant to binary 10¶
Generate 62 random bits and fill in 8-bits for seq_or_node and 54-bits for the node.¶
Format by concatenating the 128-bits as: timestamp_32|timestamp_48|version|time_or_node|variant|seq_or_node|node¶
Save the state (current timestamp and clock sequence) back to the stable store¶
48-bit timestamp, 12-bit sequence counter, 62-bit node:¶
From a system-wide shared stable store (e.g., a file) or global variable, read the UUID generator state: the values of the timestamp and clock sequence used to generate the last UUID.¶
Obtain the current time from the selected clock source as 32 bits.¶
Set the 32-bit field timestamp_32 to the 32 most significant bits from the timestamp¶
Set 16-bit timestamp_48 to the 16 least significant bits from the timestamp¶
The rest of the steps are the same as the previous example.¶
60-bit timestamp, 8-bit sequence counter, 54-bit node:¶
From a system-wide shared stable store (e.g., a file) or global variable, read the UUID generator state: the values of the timestamp and clock sequence used to generate the last UUID.¶
Obtain the current time from the selected clock source as 32 bits.¶
Set the 32-bit field timestamp_32 to the 32 bits from the timestamp¶
Set 16-bit timestamp_48 to the 16 middle bits from the timestamp¶
Set the version to 8 (1000)¶
Set 12-bit time_or_node to the 12 least significant bits from the timestamp¶
Set the variant to 10¶
If the state was unavailable (e.g., non-existent or corrupted) or the timestamp is greater than the current timestamp; set the 12-bit clock sequence value (seq_or_node) to 0¶
If the state was available, but the saved timestamp is less than or equal to the current timestamp, increment the clock sequence value (seq_or_node).¶
Generate 54 random bits and fill in the node¶
Format by concatenating the 128-bits as: timestamp_32|timestamp_48|version|time_or_node|variant|seq_or_node|node¶
Save the state (current timestamp and clock sequence) back to the stable store¶
64-bit timestamp, 8-bit sequence counter, 54-bit node:¶
The same steps as the 60-bit timestamp can be utilized if the 64-bit timestamp is truncated to 60-bits.¶
Implementations MAY chose to truncate the most or least significant bits but it is recommended to utilize the most significant 60-bits and lose 4 bits of precision in the nanoseconds or microseconds position.¶
General algorithm for generation of UUIDv8 not defined here:¶
From a system-wide shared stable store (e.g., a file) or global variable, read the UUID generator state: the values of the timestamp and clock sequence used to generate the last UUID.¶
Obtain the current time from the selected clock source as desired bit total¶
Set total amount of bits for timestamp as required in the most significant positions of the 128-bit UUID¶
Care MUST be taken to ensure that the UUID Version and UUID Variant are in the correct bit positions.¶
UUID Version: Bits 48 through 51¶
UUID Variant: Bits 64 and 65¶
If the state was unavailable (e.g., non-existent or corrupted) or the timestamp is greater than the current timestamp; set the desired clock sequence value to 0¶
If the state was available, but the saved timestamp is less than or equal to the current timestamp, increment the clock sequence value.¶
Set the remaining bits to the node as pseudo-random data¶
Format by concatenating the 128-bits together¶
Save the state (current timestamp and clock sequence) back to the stable store¶
The existing UUID hex and dash format of 8-4-4-4-12 is retained for both backwards compatibility and human readability.¶
For many applications such as databases this format is unnecessarily verbose totaling 288 bits.¶
Where possible UUIDs SHOULD be stored within database applications as the underlying 128-bit binary value.¶
UUIDs created by this specification offer the same guarantees for global uniqueness as those found in [RFC4122]. Furthermore, the time-based UUIDs defined in this specification are geared towards database applications but MAY be used for a wide variety of use-cases. Just as global uniqueness is guaranteed, UUIDs are guaranteed to be unique within an application context within the enterprise domain.¶
Some implementations might desire to utilize multi-node, clustered, applications which involve 2 or more applications independently generating UUIDs that will be stored in a common location. UUIDs already feature sufficient entropy to ensure that the chances of collision are low. However, implementations MAY dedicate a portion of the node's most significant random bits to a pseudo-random machineID which helps identify UUIDs created by a given node. This works to add an extra layer of collision avoidance.¶
This machine ID MUST be placed in the UUID proceeding the timestamp and sequence counter bits. This position is selected to ensure that the sorting by timestamp and clock sequence is still possible. The machineID MUST NOT be an IEEE 802 MAC address. The creation and negotiation of the machineID among distributed nodes is out of scope for this specification.¶
This document has no IANA actions.¶
MAC addresses pose inherent security risks and MUST not be used for node generation. As such they have been strictly forbidden from time-based UUIDs within this specification. Instead pseudo-random bits SHOULD selected from a source with sufficient entropy to ensure guaranteed uniqueness among UUID generation.¶
Timestamps embedded in the UUID do pose a very small attack surface. The timestamp in conjunction with the clock sequence does signal the order of creation for a given UUID and it's corresponding data but does not define anything about the data itself or the application as a whole. If UUIDs are required for use with any security operation within an application context in any shape or form then [RFC4122] UUIDv4 SHOULD be utilized.¶
The machineID portion of node, described in Section 7, does provide small unique identifier which could be used to determine which application is generating data but this machineID alone is not enough to identify a node on the network without other corresponding data points. Furthermore the machineID, like the timestamp+sequence, does not provide any context about the data the corresponds to the UUID or the current state of the application as a whole.¶
The authors gratefully acknowledge the contributions of Ben Campbell, Ben Ramsey, Fabio Lima, Gonzalo Salgueiro, Martin Thomson, Murray S. Kucherawy, Rick van Rein, Rob Wilton, Sean Leonard, Theodore Y. Ts'o. As well as all of those in and outside the IETF community to who contributed to the discussions which resulted in this document.¶
| Msb0 | Msb1 | Msb2 | Msb3 | Version | Description |
| 0 | 1 | 1 | 0 | 6 | Reordered Gregorian time-based UUID |
| 0 | 1 | 1 | 1 | 7 | Variable length Unix Epoch time-based UUID |
| 1 | 0 | 0 | 0 | 8 | Custom time-based UUID |
| Msb0 | Msb1 | Msb2 | Description |
| 1 | 0 | x | The variant specified in this document. |
| UUIDv1 Field | Bits | UUIDv6 Field |
| time_low | 32 | time_high |
| time_mid | 16 | time_mid |
| time_high | 12 | time_low |
| Internet-Draft | new-uuid-format | August 2021 |
| Peabody & Davis | Expires 27 February 2022 | [Page] |
This document presents new time-based UUID formats which are suited for use as a database key.¶
A common case for modern applications is to create a unique identifier for use as a primary key in a database table. This identifier usually implements an embedded timestamp that is sortable using the monotonic creation time in the most significant bits. In addition the identifier is highly collision resistant, difficult to guess, and provides minimal security attack surfaces. None of the existing UUID versions, including UUIDv1, fulfill each of these requirements in the most efficient possible way. This document is a proposal to update [RFC4122] with three new UUID versions that address these concerns, each with different trade-offs.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 27 February 2022.¶
Copyright (c) 2021 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) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119].¶
A lot of things have changed in the time since UUIDs were originally created. Modern applications have a need to use (and many have already implemented) UUIDs as database primary keys.¶
The motivation for using UUIDs as database keys stems primarily from the fact that applications are increasingly distributed in nature. Simplistic "auto increment" schemes with integers in sequence do not work well in a distributed system since the effort required to synchronize such numbers across a network can easily become a burden. The fact that UUIDs can be used to create unique and reasonably short values in distributed systems without requiring synchronization makes them a good candidate for use as a database key in such environments.¶
However some properties of [RFC4122] UUIDs are not well suited to this task. First, most of the existing UUID versions such as UUIDv4 have poor database index locality. Meaning new values created in succession are not close to each other in the index and thus require inserts to be performed at random locations. The negative performance effects of which on common structures used for this (B-tree and its variants) can be dramatic. As such newly inserted values SHOULD be time-ordered to address this.¶
While it is true that UUIDv1 does contain an embedded timestamp and can be time-ordered; UUIDv1 has other issues. It is possible to sort Version 1 UUIDs by time but it is a laborious task. The process requires breaking the bytes of the UUID into various pieces, re-ordering the bits, and then determining the order from the reconstructed timestamp. This is not efficient in very large systems. Implementations would be simplified with a sort order where the UUID can simply be treated as an opaque sequence of bytes and ordered as such.¶
After the embedded timestamp, the remaining 64 bits are in essence used to provide uniqueness both on a global scale and within a given timestamp tick. The clock sequence value ensures that when multiple UUIDs are generated for the same timestamp value are given a monotonic sequence value. This explicit sequencing helps further facilitate sorting. The remaining random bits ensure collisions are minimal.¶
Furthermore, UUIDv1 utilizes a non-standard timestamp epoch derived from the Gregorian Calendar. More specifically, the Coordinated Universal Time (UTC) as a count of 100-nanosecond intervals since 00:00:00.00, 15 October 1582. Implementations and many languages may find it easier to implement the widely adopted and well known Unix Epoch, a custom epoch, or another timestamp source with various levels of timestamp precision required by the application.¶
Lastly, privacy and network security issues arise from using a MAC address in the node field of Version 1 UUIDs. Exposed MAC addresses can be used as an attack surface to locate machines and reveal various other information about such machines (minimally manufacturer, potentially other details). Instead "cryptographically secure" pseudo-random number generators (CSPRNGs) or pseudo-random number generators (PRNG) SHOULD be used within an application context to provide uniqueness and unguessability.¶
Due to the shortcomings of UUIDv1 and UUIDv4 details so far, many widely distributed database applications and large application vendors have sought to solve the problem of creating a better time-based, sortable unique identifier for use as a database key. This has lead to numerous implementations over the past 10+ years solving the same problem in slightly different ways.¶
While preparing this specification the following 16 different implementations were analyzed for trends in total ID length, bit Layout, lexical formatting/encoding, timestamp type, timestamp format, timestamp accuracy, node format/components, collision handling and multi-timestamp tick generation sequencing.¶
[LexicalUUID] by Twitter¶
[ShardingID] by Instagram¶
[Elasticflake] by P. Pearcy¶
[orderedUuid] by IT. Cabrera¶
An inspection of these implementations details the following trends that help define this standard:¶
- Timestamps MUST be k-sortable. That is, values within or close to the same timestamp are ordered properly by sorting algorithms.¶
- Timestamps SHOULD be big-endian with the most-significant bits of the time embedded as-is without reordering.¶
- Timestamps SHOULD utilize millisecond precision and Unix Epoch as timestamp source. Although, there is some variation to this among implementations depending on the application requirements.¶
- The ID format SHOULD be Lexicographically sortable while in the textual representation.¶
- IDs MUST ensure proper embedded sequencing to facilitate sorting when multiple UUIDs are created during a given timestamp.¶
- IDs MUST NOT require unique network identifiers as part of achieving uniqueness.¶
- Distributed nodes MUST be able to create collision resistant Unique IDs without consulting a centralized resource.¶
In order to solve these challenges this specification introduces three new version identifiers assigned for time-based UUIDs.¶
The first, UUIDv6, aims to be the easiest to implement for applications which already implement UUIDv1. The UUIDv6 specification keeps the original Gregorian timestamp source but does not reorder the timestamp bits as per the process utilized by UUIDv1. UUIDv6 also requires that pseudo-random data MUST be used in place of the MAC address. The rest of the UUIDv1 format remains unchanged in UUIDv6. See Section 4.3¶
Next, UUIDv7 introduces an entirely new time-based UUID bit layout utilizing a variable length timestamp sourced from the widely implemented and well known Unix Epoch timestamp source. The timestamp is broken into a 36 bit integer sections part, and is followed by a field of variable length which represents the sub-second timestamp portion, encoded so that each bit from most to least significant adds more precision. See Section 4.4¶
Finally, UUIDv8 introduces a relaxed time-based UUID format that caters to application implementations that cannot utilize UUIDv1, UUIDv6, or UUIDv7. UUIDv8 also future-proofs this specification by allowing time-based UUID formats from timestamp sources that are not yet be defined. The variable size timestamp offers lots of flexibility to create an implementation specific RFC compliant time-based UUID while retaining the properties that make UUID great. See Section 4.5¶
RFC EDITOR PLEASE DELETE THIS SECTION.¶
draft-02¶
- Added Changelog¶
- Fixed misc. grammatical errors¶
- Fixed section numbering issue¶
- Fixed some UUIDvX reference issues¶
- Changed all instances of "motonic" to "monotonic"¶
- Changed all instances of "#-bit" to "# bit"¶
- Changed "proceeding" veriage to "after" in section 7¶
- Added details on how to pad 32 bit unix timestamp to 36 bits in UUIDv7¶
- Added details on how to truncate 64 bit unix timestamp to 36 bits in UUIDv7¶
- Added forward reference and bullet to UUIDv8 if truncating 64 bit Unix Epoch is not an option.¶
- Fixed bad reference to non-existent "time_or_node" in section 4.5.4¶
draft-01¶
- Complete rewrite of entire document.¶
- The format, flow and verbiage used in the specification has been reworked to mirror the original RFC 4122 and current IETF standards.¶
- Removed the topics of UUID length modification, alternate UUID text formats, and alternate UUID encoding techniques.¶
- Research into 16 different historical and current implementations of time-based universal identifiers was completed at the end of 2020 in attempt to identify trends which have directly influenced design decisions in this draft document (https://github.com/uuid6/uuid6-ietf-draft/tree/master/research)¶
- Prototype implementation have been completed for UUIDv6, UUIDv7, and UUIDv8 in various languages by many GitHub community members. (https://github.com/uuid6/prototypes)¶
The UUID length of 16 octets (128 bits) remains unchanged. The textual representation of a UUID consisting of 36 hexadecimal and dash characters in the format 8-4-4-4-12 remains unchanged for human readability. In addition the position of both the Version and Variant bits remain unchanged in the layout.¶
Table 1 defines the 4 bit version found in Bits 48 through 51 within a given UUID.¶
| Msb0 | Msb1 | Msb2 | Msb3 | Version | Description |
| 0 | 1 | 1 | 0 | 6 | Reordered Gregorian time-based UUID |
| 0 | 1 | 1 | 1 | 7 | Variable length Unix Epoch time-based UUID |
| 1 | 0 | 0 | 0 | 8 | Custom time-based UUID |
The variant bits utilized by UUIDs in this specification remains the same as [RFC4122], Section 4.1.1.¶
The Table 2 lists the contents of the variant field, bits 64 and 65, where the letter "x" indicates a "don't-care" value. Common hex values of 8 (1000), 9 (1001), A (1010), and B (1011) frequent the text representation.¶
| Msb0 | Msb1 | Msb2 | Description |
| 1 | 0 | x | The variant specified in this document. |
UUIDv6 aims to be the easiest to implement by reusing most of the layout of bits found in UUIDv1 but with changes to bit ordering for the timestamp. Where UUIDv1 splits the timestamp bits into three distinct parts and orders them as time_low, time_mid, time_high_and_version. UUIDv6 instead keeps the source bits from the timestamp intact and changes the order to time_high, time_mid, and time_low. Incidentally this will match the original 60 bit Gregorian timestamp source with 100-nanosecond precision defined in [RFC4122], Section 4.1.4 The clock sequence bits remain unchanged from their usage and position in [RFC4122], Section 4.1.5. The 48 bit node SHOULD be set to a pseudo-random value however implementations MAY choose retain the old MAC address behavior from [RFC4122], Section 4.1.6 and [RFC4122], Section 4.5¶
The format for the 16-octet, 128 bit UUIDv6 is shown in Figure 1¶
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 | time_low_and_version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|clk_seq_hi_res | clk_seq_low | node (0-1) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| node (2-5) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The following implementation algorithm is based on [RFC4122] but with changes specific to UUIDv6:¶
From a system-wide shared stable store (e.g., a file) or global variable, read the UUID generator state: the values of the timestamp and clock sequence used to generate the last UUID.¶
Obtain the current time as a 60 bit count of 100-nanosecond intervals since 00:00:00.00, 15 October 1582.¶
Set the time_low field to the 12 least significant bits of the starting 60 bit timestamp.¶
Truncate the timestamp to the 48 most significant bits in order to create time_high_and_time_mid.¶
Set the time_high field to the 32 most significant bits of the truncated timestamp.¶
Set the time_mid field to the 16 least significant bits of the truncated timestamp.¶
Create the 16 bit time_low_and_version by concatenating the 4 bit UUIDv6 version with the 12 bit time_low.¶
If the state was unavailable (e.g., non-existent or corrupted) or the timestamp is greater than the current timestamp generate a random 14 bit clock sequence value.¶
If the state was available, but the saved timestamp is less than or equal to the current timestamp, increment the clock sequence value.¶
Complete the 16 bit clock sequence high, low and reserved creation by concatenating the clock sequence onto UUID variant bits which take the most significant position in the 16 bit value.¶
Generate a 48 bit pseudo-random node.¶
Format by concatenating the 128 bits from each parts: time_high|time_mid|time_low_and_version|variant_clk_seq|node¶
Save the state (current timestamp and clock sequence) back to the stable store¶
The steps for splitting time_high_and_time_mid into time_high and time_mid are optional since the 48 bits of time_high and time_mid will remain in the same order as time_high_and_time_mid during the final concatenation. This extra step of splitting into the most significant 32 bits and least significant 16 bits proves useful when reusing an existing UUIDv1 implementation. In which the following logic can be applied to reshuffle the bits with minimal modifications.¶
| UUIDv1 Field | Bits | UUIDv6 Field |
| time_low | 32 | time_high |
| time_mid | 16 | time_mid |
| time_high | 12 | time_low |
The UUIDv7 format is designed to encode a Unix timestamp with arbitrary sub-second precision. The key property provided by UUIDv7 is that timestamp values generated by one system and parsed by another are guaranteed to have sub-second precision of either the generator or the parser, whichever is less. Additionally, the system parsing the UUIDv7 value does not need to know which precision was used during encoding in order to function correctly.¶
The format for the 16-octet, 128 bit UUIDv7 is shown in Figure 2¶
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unixts |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|unixts | subsec_a | ver | subsec_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| subsec_seq_node |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| subsec_seq_node |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
UUIDv7 utilizes a 36 bit big-endian unsigned Unix Timestamp value (number of seconds since the epoch of 1 Jan 1970, leap seconds excluded so each hour is exactly 3600 seconds long). The 36 bit value was selected in order to provide more available time to the unix timestamp and avoid the Year 2038 problem by extending the maximum timestamp to the year 4147.¶
To achieve a 36 bit UUIDv7 timestamp, the lower 36 bits of a 64 bit unix time are extracted verbatim into UUIDv7¶
In the event that 32 bit Unix Timestamp are in use; four zeros MUST be appended at the start in the most significant (left-most) bits of the 32 bit Unix timestamp creating the 36 bit Unix timestamp. This ensures sorting compatibility with 64 bit unix timestamp which have been truncated to 36 bits.¶
Additional sub-second precision (millisecond, nanosecond, microsecond, etc) MAY be provided for encoding and decoding in the remaining bits in the layout.¶
UUIDv8 SHOULD be used in place of UUIDv7 if an application or implementation does not want to truncate a 64 bit Unix Epoch to the lower 36 bits.¶
UUIDv7 SHOULD utilize a monotonic sequence counter to provide additional sequencing guarantees when multiple UUIDv7 values are created in the same UNIXTS and SUBSEC timestamp. The amount of bits allocates to the sequence counter depend on the precision of the timestamp. For example, a more accurate timestamp source using nanosecond precision will require less clock sequence bits than a timestamp source utilizing seconds for precision. For best sequencing results the sequence counter SHOULD be placed immediately after available sub-second bits.¶
The clock sequence MUST start at zero and increment monotonically for each new UUIDv7 created on by the application on the same timestamp. When the timestamp increments the clock sequence MUST be reset to zero. The clock sequence MUST NOT rollover or reset to zero unless the timestamp has incremented. Care MUST be given to ensure that an adequate sized clock sequence is selected for a given application based on expected timestamp precision and expected UUIDv7 generation rates.¶
UUIDv7 implementations, even with very detailed sub-second precision and the optional sequence counter, MAY have leftover bits that will be identified as the Node for this section. The UUIDv7 Node MAY contain any set of data an implementation desires however the node MUST NOT be set to all 0s which does not ensure global uniqueness. In most scenarios the node SHOULD be filled with pseudo-random data.¶
The UUIDv7 bit layout for encoding and decoding are described separately in this document.¶
Since the UUIDv7 Unix timestamp is fixed at 36 bits in length the exact layout for encoding UUIDv7 depends on the precision (number of bits) used for the sub-second portion and the sizes of the optionally desired sequence counter and node bits.¶
Three examples of UUIDv7 encoding are given below as a general guidelines but implementations are not limited to just these three examples.¶
All of these fields are only used during encoding, and during decoding the system is unaware of the bit layout used for them and considers this information opaque. As such, implementations generating these values can assign whatever lengths to each field it deems applicable, as long as it does not break decoding compatibility (i.e. Unix timestamp (unixts), version (ver) and variant (var) have to stay where they are, and clock sequence counter (seq), random (random) or other implementation specific values must follow the sub-second encoding).¶
In Figure 3 the UUIDv7 has been created with millisecond precision with the available sub-second precision bits.¶
Examining Figure 3 one can observe:¶
The first 36 bits have been dedicated to the Unix Timestamp (unixts)¶
All 12 bits of scenario subsec_a is fully dedicated to millisecond information (msec).¶
The 4 Version bits remain unchanged (ver).¶
All 12 bits of subsec_b have been dedicated to a monotonic clock sequence counter (seq).¶
The 2 Variant bits remain unchanged (var).¶
Finally the remaining 62 bits in the subsec_seq_node section are layout is filled out with random data to pad the length and provide guaranteed uniqueness (rand).¶
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unixts |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|unixts | msec | ver | seq |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| rand |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rand |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
In Figure 4 the UUIDv7 has been created with Microsecond precision with the available sub-second precision bits.¶
Examining Figure 4 one can observe:¶
The first 36 bits have been dedicated to the Unix Timestamp (unixts)¶
All 12 bits of scenario subsec_a is fully dedicated to providing sub-second encoding for the Microsecond precision (usec).¶
The 4 Version bits remain unchanged (ver).¶
All 12 bits of subsec_b have been dedicated to providing sub-second encoding for the Microsecond precision (usec).¶
The 2 Variant bits remain unchanged (var).¶
A 14 bit monotonic clock sequence counter (seq) has been embedded in the most significant position of subsec_seq_node¶
Finally the remaining 48 bits in the subsec_seq_node section are layout is filled out with random data to pad the length and provide guaranteed uniqueness (rand).¶
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unixts |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|unixts | usec | ver | usec |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| seq | rand |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rand |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
In Figure 5 the UUIDv7 has been created with Nanosecond precision with the available sub-second precision bits.¶
Examining Figure 5 one can observe:¶
The first 36 bits have been dedicated to the Unix Timestamp (unixts)¶
All 12 bits of scenario subsec_a is fully dedicated to providing sub-second encoding for the Nanosecond precision (nsec).¶
The 4 Version bits remain unchanged (ver).¶
All 12 bits of subsec_b have been dedicated to providing sub-second encoding for the Nanosecond precision (nsec).¶
The 2 Variant bits remain unchanged (var).¶
The first 14 bit of the subsec_seq_node dedicated to providing sub-second encoding for the Nanosecond precision (nsec).¶
The next 8 bits of subsec_seq_node dedicated a monotonic clock sequence counter (seq).¶
Finally the remaining 40 bits in the subsec_seq_node section are layout is filled out with random data to pad the length and provide guaranteed uniqueness (rand).¶
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unixts |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|unixts | nsec | ver | nsec |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| nsec | seq | rand |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rand |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
When decoding or parsing a UUIDv7 value there are only two values to be considered:¶
The unix timestamp defined as unixts¶
The sub-second precision values defined as subsec_a, subsec_b, and subsec_seq_node¶
As detailed in Figure 2 the unix timestamp (unixts) is always the first 36 bits of the UUIDv7 layout.¶
Similarly as per Figure 2, the sub-second precision values lie within subsec_a, subsec_b, and subsec_seq_node which are all interpreted as sub-second information after skipping over the version (ver) and (var) bits. These concatenated sub-second information bits are interpreted in a way where most to least significant bits represent a further division by two. This is the same normal place notation used to express fractional numbers, except in binary. For example, in decimal ".1" means one tenth, and ".01" means one hundredth. In this subsec field, a 1 means one half, 01 means one quarter, 001 is one eighth, etc. This scheme can work for any number of bits up to the maximum available, and keeps the most significant data leftmost in the bit sequence.¶
To perform the sub-second math, simply take the first (most significant/leftmost) N bits of subsec and divide it by 2^N. Take for example:¶
To parse the first 16 bits, extract that value as an integer and divide it by 65536 (2 to the 16th).¶
If these 16 bits are 0101 0101 0101 0101, then treating that as an integer gives 0x5555 or 21845 in decimal, and dividing by 65536 gives 0.3333282¶
This sub-second encoding scheme provides maximum interoperability across systems where different levels of time precision are required/feasible/available. The timestamp value derived from a UUIDv7 value SHOULD be "as close to the correct value as possible" when parsed, even across disparate systems.¶
Take for example the starting point for our next two UUIDv7 parsing scenarios:¶
Scenario 1:¶
Scenario 2:¶
UUIDv8 offers variable-size timestamp, clock sequence, and node values which allow for a highly customizable UUID that fits a given application needs.¶
UUIDv8 SHOULD only be utilized if an implementation cannot utilize UUIDv1, UUIDv6, or UUIDv7. Some situations in which UUIDv8 usage could occur:¶
An implementation would like to utilize a timestamp source not defined by the current time-based UUIDs.¶
An implementation would like to utilize a timestamp bit layout not defined by the current time-based UUIDs.¶
An implementation would like to avoid truncating a 64 bit Unix to 36 bits as defined by UUIDv7.¶
An implementation would like a specific level of precision within the timestamp not offered by current time-based UUIDs.¶
An implementation would like to embed extra information within the UUID node other than what is defined in this document.¶
An implementation has other application/language restrictions which inhibit the usage of one of the current time-based UUIDs.¶
Roughly speaking a properly formatted UUIDv8 SHOULD contain the following sections adding up to a total of 128 bits.¶
- Timestamp Bits (Variable Length)¶
- Clock Sequence Bits (Variable Length)¶
- Node Bits (Variable Length)¶
- UUIDv8 Version Bits (4 bits)¶
- UUID Variant Bits (2 Bits)¶
The only explicitly defined bits are the Version and Variant leaving 122 bits for implementation specific time-based UUIDs. To be clear: UUIDv8 is not a replacement for UUIDv4 where all 122 extra bits are filled with random data. UUIDv8's 128 bits (including the version and variant) SHOULD contain at the minimum a timestamp of some format in the most significant bit position followed directly by a clock sequence counter and finally a node containing either random data or implementation specific data.¶
A sample format in Figure 6 is used to further illustrate the point for the 16-octet, 128 bit UUIDv8.¶
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp_32 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp_48 | ver | time_or_seq |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| seq_or_node | node |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| node |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
UUIDv8's usage of timestamp relaxes both the timestamp source and timestamp length. Implementations are free to utilize any monotonically stable timestamp source for UUIDv8.¶
Some examples include:¶
- Custom Epoch¶
- NTP timestamp¶
- ISO 8601 timestamp¶
- Full, Non-truncated 64 bit Unix Epoch timestamp¶
The relaxed nature UUIDv8 timestamps also works to future proof this specification and allow implementations a method to create compliant time-based UUIDs using timestamp source that might not yet be defined.¶
Timestamps come in many sizes and UUIDv8 defines three fields that can easily used for the majority of timestamp lengths:¶
32 bit timestamp: using timestamp_32 and setting timestamp_48 to 0s¶
48 bit timestamp: using timestamp_32 and timestamp_48 entirely¶
60 bit timestamp: using timestamp_32, timestamp_48, and time_or_seq¶
64 bit timestamp: using timestamp_32, timestamp_48, and time_or_seq and truncating the timestamp the 60 most significant bits.¶
Although it is possible to create a timestamp larger than 64 bits in size The usage and bit layout of that timestamp format is up to the implementation. When a timestamp exceeds the 64th bit (octet 7), extra care must be taken to ensure the Variant bits are properly inserted at their respective location in the UUID. Likewise, the Version MUST always be implemented at the appropriate location.¶
Any timestamps that does not entirely fill the timestamp_32, timestamp_48 or time_or_seq MUST set all leftover bits in the least significant position of the respective field to 0. For example a 36 bit timestamp source would fully utilize timestamp_32 and 4 bits of timestamp_48. The remaining 12 bits in timestamp_48 MUST be set to 0.¶
By using implementation-specific timestamp sources it is not guaranteed that devices outside of the application context are able to extract and parse the timestamp from UUIDv8 without some pre-existing knowledge of the source timestamp used by the UUIDv8 implementation.¶
A clock sequence MUST be used with UUIDv8 as added sequencing guarantees when multiple UUIDv8 will be created on the same clock tick. The amount of bits allocated to the clock sequence depends on the precision of the timestamp source. For example, a more accurate timestamp source using nanosecond precision will require less clock sequence bits than a timestamp source utilizing seconds for precision.¶
The UUIDv8 layout in Figure 6 generically defines two possible clock sequence values that can leveraged:¶
12 bit clock sequence using time_or_seq for use when the timestamp is less than 48 bits which allows for 4095 UUIDs per clock tick.¶
8 bit clock sequence using seq_or_node when the timestamp uses more than 48 bits which allows for 255 UUIDs per clock tick.¶
An implementation MAY use both time_or_seq and seq_or_node for clock sequencing however it is highly unlikely that 20 bits of clock sequence are needed for a given clock tick. Furthermore, more bits from the node MAY be used for clock sequencing in the event that 8 bits is not sufficient.¶
The clock sequence MUST start at zero and increment monotonically for each new UUIDv8 created on by the application on the same timestamp. When the timestamp increments the clock sequence MUST be reset to zero. The clock sequence MUST NOT rollover or reset to zero unless the timestamp has incremented. Care MUST be given to ensure that an adequate sized clock sequence is selected for a given application based on expected timestamp precision and expected UUIDv8 generation rates.¶
The UUIDv8 Node MAY contain any set of data an implementation desires however the node MUST NOT be set to all 0s which does not ensure global uniqueness. In most scenarios the node will be filled with pseudo-random data.¶
The UUIDv8 layout in Figure 6 defines 2 sizes of Node depending on the timestamp size:¶
62 bit node encompassing seq_or_node and node Used when a timestamp of 48 bits or less is leveraged.¶
54 bit node when all 60 bits of the timestamp are in use and the seq_or_node is used as clock sequencing.¶
An implementation MAY choose to allocate bits from the node to the timestamp, clock sequence or application-specific embedded field. It is recommended that implementation utilize a node of at least 48 bits to ensure global uniqueness can be guaranteed.¶
The entire usage of UUIDv8 is meant to be variable and allow as much customization as possible to meet specific application/language requirements. As such any UUIDv8 implementations will likely vary among applications.¶
The following algorithm is a generic implementation using Figure 6 and the recommendations outlined in this specification.¶
32 bit timestamp, 12 bit sequence counter, 62 bit node:¶
From a system-wide shared stable store (e.g., a file) or global variable, read the UUID generator state: the values of the timestamp and clock sequence used to generate the last UUID.¶
Obtain the current time from the selected clock source as 32 bits.¶
Set the 32 bit field timestamp_32 to the 32 bits from the timestamp¶
Set 16 bit timestamp_48 to all 0s¶
Set the version to 8 (1000)¶
If the state was unavailable (e.g., non-existent or corrupted) or the timestamp is greater than the current timestamp; set the 12 bit clock sequence value (time_or_seq) to 0¶
If the state was available, but the saved timestamp is less than or equal to the current timestamp, increment the clock sequence value (time_or_seq).¶
Set the variant to binary 10¶
Generate 62 random bits and fill in 8 bits for seq_or_node and 54 bits for the node.¶
Format by concatenating the 128 bits as: timestamp_32|timestamp_48|version|time_or_seq|variant|seq_or_node|node¶
Save the state (current timestamp and clock sequence) back to the stable store¶
48 bit timestamp, 12 bit sequence counter, 62 bit node:¶
From a system-wide shared stable store (e.g., a file) or global variable, read the UUID generator state: the values of the timestamp and clock sequence used to generate the last UUID.¶
Obtain the current time from the selected clock source as 32 bits.¶
Set the 32 bit field timestamp_32 to the 32 most significant bits from the timestamp¶
Set 16 bit timestamp_48 to the 16 least significant bits from the timestamp¶
The rest of the steps are the same as the previous example.¶
60 bit timestamp, 8 bit sequence counter, 54 bit node:¶
From a system-wide shared stable store (e.g., a file) or global variable, read the UUID generator state: the values of the timestamp and clock sequence used to generate the last UUID.¶
Obtain the current time from the selected clock source as 32 bits.¶
Set the 32 bit field timestamp_32 to the 32 bits from the timestamp¶
Set 16 bit timestamp_48 to the 16 middle bits from the timestamp¶
Set the version to 8 (1000)¶
Set 12 bit time_or_seq to the 12 least significant bits from the timestamp¶
Set the variant to 10¶
If the state was unavailable (e.g., non-existent or corrupted) or the timestamp is greater than the current timestamp; set the 12 bit clock sequence value (seq_or_node) to 0¶
If the state was available, but the saved timestamp is less than or equal to the current timestamp, increment the clock sequence value (seq_or_node).¶
Generate 54 random bits and fill in the node¶
Format by concatenating the 128 bits as: timestamp_32|timestamp_48|version|time_or_seq|variant|seq_or_node|node¶
Save the state (current timestamp and clock sequence) back to the stable store¶
64 bit timestamp, 8 bit sequence counter, 54 bit node:¶
The same steps as the 60 bit timestamp can be utilized if the 64 bit timestamp is truncated to 60 bits.¶
Implementations MAY chose to truncate the most or least significant bits but it is recommended to utilize the most significant 60 bits and lose 4 bits of precision in the nanoseconds or microseconds position.¶
General algorithm for generation of UUIDv8 not defined here:¶
From a system-wide shared stable store (e.g., a file) or global variable, read the UUID generator state: the values of the timestamp and clock sequence used to generate the last UUID.¶
Obtain the current time from the selected clock source as desired bit total¶
Set total amount of bits for timestamp as required in the most significant positions of the 128 bit UUID¶
Care MUST be taken to ensure that the UUID Version and UUID Variant are in the correct bit positions.¶
UUID Version: Bits 48 through 51¶
UUID Variant: Bits 64 and 65¶
If the state was unavailable (e.g., non-existent or corrupted) or the timestamp is greater than the current timestamp; set the desired clock sequence value to 0¶
If the state was available, but the saved timestamp is less than or equal to the current timestamp, increment the clock sequence value.¶
Set the remaining bits to the node as pseudo-random data¶
Format by concatenating the 128 bits together¶
Save the state (current timestamp and clock sequence) back to the stable store¶
The existing UUID hex and dash format of 8-4-4-4-12 is retained for both backwards compatibility and human readability.¶
For many applications such as databases this format is unnecessarily verbose totaling 288 bits.¶
Where possible UUIDs SHOULD be stored within database applications as the underlying 128 bit binary value.¶
UUIDs created by this specification offer the same guarantees for global uniqueness as those found in [RFC4122]. Furthermore, the time-based UUIDs defined in this specification are geared towards database applications but MAY be used for a wide variety of use-cases. Just as global uniqueness is guaranteed, UUIDs are guaranteed to be unique within an application context within the enterprise domain.¶
Some implementations might desire to utilize multi-node, clustered, applications which involve 2 or more applications independently generating UUIDs that will be stored in a common location. UUIDs already feature sufficient entropy to ensure that the chances of collision are low. However, implementations MAY dedicate a portion of the node's most significant random bits to a pseudo-random machineID which helps identify UUIDs created by a given node. This works to add an extra layer of collision avoidance.¶
This machine ID MUST be placed in the UUID after the timestamp and sequence counter bits. This position is selected to ensure that the sorting by timestamp and clock sequence is still possible. The machineID MUST NOT be an IEEE 802 MAC address. The creation and negotiation of the machineID among distributed nodes is out of scope for this specification.¶
This document has no IANA actions.¶
MAC addresses pose inherent security risks and MUST not be used for node generation. As such they have been strictly forbidden from time-based UUIDs within this specification. Instead pseudo-random bits SHOULD selected from a source with sufficient entropy to ensure guaranteed uniqueness among UUID generation.¶
Timestamps embedded in the UUID do pose a very small attack surface. The timestamp in conjunction with the clock sequence does signal the order of creation for a given UUID and it's corresponding data but does not define anything about the data itself or the application as a whole. If UUIDs are required for use with any security operation within an application context in any shape or form then [RFC4122] UUIDv4 SHOULD be utilized.¶
The machineID portion of node, described in Section 7, does provide small unique identifier which could be used to determine which application is generating data but this machineID alone is not enough to identify a node on the network without other corresponding data points. Furthermore the machineID, like the timestamp+sequence, does not provide any context about the data the corresponds to the UUID or the current state of the application as a whole.¶
The authors gratefully acknowledge the contributions of Ben Campbell, Ben Ramsey, Fabio Lima, Gonzalo Salgueiro, Martin Thomson, Murray S. Kucherawy, Rick van Rein, Rob Wilton, Sean Leonard, Theodore Y. Ts'o. As well as all of those in and outside the IETF community to who contributed to the discussions which resulted in this document.¶
| Msb0 | Msb1 | Msb2 | Msb3 | Version | Description |
| 0 | 1 | 1 | 0 | 6 | Reordered Gregorian time-based UUID |
| 0 | 1 | 1 | 1 | 7 | Variable length Unix Epoch time-based UUID |
| 1 | 0 | 0 | 0 | 8 | Custom time-based UUID |
| Msb0 | Msb1 | Msb2 | Description |
| 1 | 0 | x | The variant specified in this document. |
| UUIDv1 Field | Bits | UUIDv6 Field |
| time_low | 32 | time_high |
| time_mid | 16 | time_mid |
| time_high | 12 | time_low |
| Internet-Draft | new-uuid-format | March 2022 |
| Peabody & Davis | Expires 2 October 2022 | [Page] |
This document presents new Universally Unique Identifier (UUID) formats for use in modern applications and databases.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 2 October 2022.¶
Copyright (c) 2022 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) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
Many things have changed in the time since UUIDs were originally created. Modern applications have a need to create and utilize UUIDs as the primary identifier for a variety of different items in complex computational systems, including but not limited to database keys, file names, machine or system names, and identifiers for event-driven transactions.¶
One area UUIDs have gained popularity is as database keys. This stems from the increasingly distributed nature of modern applications. In such cases, "auto increment" schemes often used by databases do not work well, as the effort required to coordinate unique numeric identifiers across a network can easily become a burden. The fact that UUIDs can be used to create unique, reasonably short values in distributed systems without requiring synchronization makes them a good alternative, but UUID versions 1-5 lack certain other desirable characteristics:¶
Non-time-ordered UUID versions such as UUIDv4 have poor database index locality. Meaning new values created in succession are not close to each other in the index and thus require inserts to be performed at random locations. The negative performance effects of which on common structures used for this (B-tree and its variants) can be dramatic.¶
The 100-nanosecond, Gregorian epoch used in UUIDv1 timestamps is uncommon and difficult to represent accurately using a standard number format such as [IEEE754].¶
Introspection/parsing is required to order by time sequence; as opposed to being able to perform a simple byte-by-byte comparison.¶
Privacy and network security issues arise from using a MAC address in the node field of Version 1 UUIDs. Exposed MAC addresses can be used as an attack surface to locate machines and reveal various other information about such machines (minimally manufacturer, potentially other details). Additionally, with the advent of virtual machines and containers, MAC address uniqueness is no longer guaranteed.¶
Many of the implementation details specified in [RFC4122] involve trade offs that are neither possible to specify for all applications nor necessary to produce interoperable implementations.¶
[RFC4122] does not distinguish between the requirements for generation of a UUID versus an application which simply stores one, which are often different.¶
Due to the aforementioned issue, many widely distributed database applications and large application vendors have sought to solve the problem of creating a better time-based, sortable unique identifier for use as a database key. This has lead to numerous implementations over the past 10+ years solving the same problem in slightly different ways.¶
While preparing this specification the following 16 different implementations were analyzed for trends in total ID length, bit Layout, lexical formatting/encoding, timestamp type, timestamp format, timestamp accuracy, node format/components, collision handling and multi-timestamp tick generation sequencing.¶
[LexicalUUID] by Twitter¶
[ShardingID] by Instagram¶
[Elasticflake] by P. Pearcy¶
[orderedUuid] by IT. Cabrera¶
An inspection of these implementations and the issues described above has led to this document which attempts to adapt UUIDs to address these issues.¶
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.¶
The following UUIDs are hereby introduced:¶
RFC EDITOR PLEASE DELETE THIS SECTION.¶
draft-03¶
- Reworked the draft body to make the content more concise¶
- UUIDv6 section reworked to just the reorder of the timestamp¶
- UUIDv7 changed to simplify timestamp mechanism to just millisecond Unix timestamp¶
- UUIDv8 relaxed to be custom in all elements except version and variant¶
- Introduced Max UUID.¶
- Added C code samples in Appendix.¶
- Added test vectors in Appendix.¶
- Version and Variant section combined into one section.¶
- Changed from pseudo-random number generators to cryptographically secure pseudo-random number generator (CSPRNG).¶
- Combined redundant topics from all UUIDs into sections such as Timestamp granularity, Monotonicity and Counters, Collision Resistance, Sorting, and Unguessability, etc.¶
- Split Encoding and Storage into Opacity and DBMS and Database Considerations¶
- Reworked Global Uniqueness under new section Global and Local Uniqueness¶
- Node verbiage only used in UUIDv6 all others reference random/rand instead¶
- Clock sequence verbiage changed simply to counter in any section other than UUIDv6¶
- Added Abbreviations section¶
- Updated IETF Draft XML Layout¶
- Added information about little-endian UUIDs¶
draft-02¶
- Added Changelog¶
- Fixed misc. grammatical errors¶
- Fixed section numbering issue¶
- Fixed some UUIDvX reference issues¶
- Changed all instances of "motonic" to "monotonic"¶
- Changed all instances of "#-bit" to "# bit"¶
- Changed "proceeding" verbiage to "after" in section 7¶
- Added details on how to pad 32 bit Unix timestamp to 36 bits in UUIDv7¶
- Added details on how to truncate 64 bit Unix timestamp to 36 bits in UUIDv7¶
- Added forward reference and bullet to UUIDv8 if truncating 64 bit Unix Epoch is not an option.¶
- Fixed bad reference to non-existent "time_or_node" in section 4.5.4¶
draft-01¶
- Complete rewrite of entire document.¶
- The format, flow and verbiage used in the specification has been reworked to mirror the original RFC 4122 and current IETF standards.¶
- Removed the topics of UUID length modification, alternate UUID text formats, and alternate UUID encoding techniques.¶
- Research into 16 different historical and current implementations of time-based universal identifiers was completed at the end of 2020 in attempt to identify trends which have directly influenced design decisions in this draft document (https://github.com/uuid6/uuid6-ietf-draft/tree/master/research)¶
- Prototype implementation have been completed for UUIDv6, UUIDv7, and UUIDv8 in various languages by many GitHub community members. (https://github.com/uuid6/prototypes)¶
The variant bits utilized by UUIDs in this specification remain in the same octet as originally defined by [RFC4122], Section 4.1.1.¶
The next table details Variant 10xx (8/9/A/B) and the new versions defined by this specification. A complete guide to all versions within this variant has been includes in Appendix C.1.¶
| Msb0 | Msb1 | Msb2 | Msb3 | Version | Description |
| 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 |
For UUID version 6, 7 and 8 the variant field placement from [RFC4122] are unchanged. An example version/variant layout for UUIDv6 follows the table where M is the version and N is the variant.¶
00000000-0000-6000-8000-000000000000 00000000-0000-6000-9000-000000000000 00000000-0000-6000-A000-000000000000 00000000-0000-6000-B000-000000000000 xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
The UUID format is 16 octets; the variant bits in conjunction with the version bits described in the next section in determine finer structure.¶
UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality. It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs. Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 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 [RFC4122], Section 4.1.4, 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 bits remain unchanged from their usage and position in [RFC4122], Section 4.1.5.¶
The 48 bit node SHOULD be set to a pseudo-random value however implementations MAY choose to retain the old MAC address behavior from [RFC4122], Section 4.1.6 and [RFC4122], Section 4.5. 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 1¶
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 | time_low_and_version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|clk_seq_hi_res | clk_seq_low | node (0-1) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| node (2-5) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
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.¶
UUID version 7 features a time-ordered value field derived from the widely implemented and well known Unix Epoch timestamp source, the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded. As well as improved entropy characteristics over versions 1 or 6.¶
Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 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 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
UUID version 8 provides an RFC-compatible format for experimental or vendor-specific use cases. The only requirement is that the variant and version bits MUST be set as defined in Section 4. UUIDv8's uniqueness will be implementation-specific and SHOULD NOT be assumed.¶
The only explicitly defined bits are the Version and Variant leaving 120 bits for implementation specific time-based UUIDs. To be clear: UUIDv8 is not a replacement for UUIDv4 where all 122 extra bits are filled with random data.¶
Some example situations in which UUIDv8 usage could occur:¶
An implementation would like to embed extra information within the UUID other than what is defined in this document.¶
An implementation has other application/language restrictions which inhibit the use of one of the current UUIDs.¶
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 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The Max UUID is 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 Nil UUID defined in [RFC4122], Section 4.1.7¶
FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF
The minimum requirements for generating UUIDs are described in this document for each version. Everything else is an implementation detail and up to the implementer to decide what is appropriate for a given implementation. That being said, various relevant factors are covered below to help guide an implementer through the different trade-offs among differing UUID implementations.¶
UUID timestamp source, precision and length was the topic of great debate while creating this specification. As such choosing the right timestamp for your application is a very important topic. This section will detail some of the most common points on this topic.¶
Monotonicity is the backbone of time-based sortable UUIDs. Naturally time-based UUIDs from this document will be monotonic due to an embedded timestamp however implementations can guarantee additional monotonicity via the concepts covered in this section.¶
Additionally, care MUST be taken to ensure UUIDs generated in batches are also monotonic. That is, if one-thousand UUIDs are generated for the same timestamp; there is sufficient logic for organizing the creation order of those one-thousand UUIDs. For batch UUID creation implementions MAY utilize a monotonic counter which SHOULD increment for each UUID created during a given timestamp.¶
For single-node UUID implementations that do not need to create batches of UUIDs, the embedded timestamp within UUID version 1, 6, and 7 can provide sufficient monotonicity guarantees by simply ensuring that timestamp increments before creating a new UUID. For the topic of Distributed Nodes please refer to Section 6.3¶
Implementations SHOULD choose one method for single-node UUID implementations that require batch UUID creation.¶
The following sub-topics cover methods behind incrementing either type of counter method:¶
The following sub-topics cover topics related solely with creating reliable fixed-length dedicated counters:¶
The following sub-topics cover rollover handling with either type of counter method:¶
Implementations MAY use the following logic to ensure UUIDs featuring 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 and type.¶
If the current timestamp is greater than the previous timestamp; re-initialize the desired counter method to the new timestamp and generate new random bytes (if the bytes were frozen or being used as the seed for a monotonic counter).¶
Implementations SHOULD check if the the currently generated UUID is greater than the previously generated UUID. If this is not the case then any number of things could have occurred. Such as, but not limited to, clock rollbacks, leap second handling or counter rollovers. Applications SHOULD embed sufficient logic to catch these scenarios and correct the problem ensuring the next UUID generated is greater than the previous.¶
Implementations SHOULD weigh the consequences of UUID collisions within their application and when deciding between UUID versions that use entropy (random) versus the other components such as Section 6.1 and Section 6.2. This is especially true for distributed node collision resistance as defined by Section 6.3.¶
There are two example scenarios below which help illustrate the varying seriousness of a collision within an application.¶
UUIDs created by this specification MAY be used to provide local uniqueness guarantees. For example, ensuring UUIDs created within a local application context are unique within a database MAY be sufficient for some implementations where global uniqueness outside of the application context, in other applications, or around the world is not required.¶
Although true global uniqueness is impossible to guarantee without a shared knowledge scheme; a shared knowledge scheme is not required by UUID to provide uniqueness guarantees. Implementations MAY implement a shared knowledge scheme introduced in Section 6.3 as they see fit to extend the uniqueness guaranteed this specification and [RFC4122].¶
Implementations SHOULD utilize a cryptographically secure pseudo-random number generator (CSPRNG) to provide values that are both difficult to predict ("unguessable") and have a low likelihood of collision ("unique"). CSPRNG ensures the best of Section 6.4 and Section 8 are present in modern UUIDs.¶
Advice on generating cryptographic-quality random numbers can be found in [RFC4086]¶
UUIDv6 and UUIDv7 are designed so that implementations that require sorting (e.g. database indexes) SHOULD sort as opaque raw bytes, without need for parsing or introspection.¶
Time ordered monotonic UUIDs benefit from greater database index locality because the new values are near each other in the index. As a result objects are more easily clustered together for better performance. The real-world differences in this approach of index locality vs random data inserts can be quite large.¶
UUIDs formats created by this specification SHOULD be Lexicographically sortable while in the textual representation.¶
UUIDs created by this specification are crafted with big-ending byte order (network byte order) in mind. If Little-endian style is required a custom UUID format SHOULD be created using UUIDv8.¶
UUIDs SHOULD be treated as opaque values and implementations SHOULD NOT examine the bits in a UUID to whatever extent is possible. However, where necessary, inspectors should refer to Section 4 for more information on determining UUID version and variant.¶
For many applications, such as databases, storing UUIDs as text is unnecessarily verbose, requiring 288 bits to represent 128 bit UUID values. Thus, where feasible, UUIDs SHOULD be stored within database applications as the underlying 128 bit binary value.¶
For other systems, UUIDs MAY be stored in binary form or as text, as appropriate. The trade-offs to both approaches are as such:¶
Storing as binary requires less space and may result in faster data access.¶
Storing as text requires more space but may require less translation if the resulting text form is to be used after retrieval and thus maybe simpler to implement.¶
DBMS vendors are encouraged to provide functionality to generate and store UUID formats defined by this specification for use as identifiers or left parts of identifiers such as, but not limited to, primary keys, surrogate keys for temporal databases, foreign keys included in polymorphic relationships, and keys for key-value pairs in JSON columns and key-value databases. Applications using a monolithic database may find using database-generated UUIDs (as opposed to client-generate UUIDs) provides the best UUID monotonicity. In addition to UUIDs, additional identifiers MAY be used to ensure integrity and feedback.¶
This document has no IANA actions.¶
MAC addresses pose inherent security risks and SHOULD not be used within a UUID. Instead CSPRNG data SHOULD be selected from a source with sufficient entropy to ensure guaranteed uniqueness among UUID generation. See Section 6.6 for more information.¶
Timestamps embedded in the UUID do pose a very small attack surface. The timestamp in conjunction with an embedded counter does signal the order of creation for a given UUID and it's corresponding data but does not define anything about the data itself or the application as a whole. If UUIDs are required for use with any security operation within an application context in any shape or form then [RFC4122] UUIDv4 SHOULD be utilized.¶
The authors gratefully acknowledge the contributions of 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, sergeyprokhorenko, LiosK As well as all of those in the IETF community and on GitHub to who contributed to the discussions which resulted in this document.¶
This section details a function in C which converts from a UUID version 1 to version 6:¶
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <arpa/inet.h>
#include <uuid/uuid.h>
/* Converts UUID version 1 to version 6 in place. */
void uuidv1tov6(uuid_t u) {
uint64_t ut;
unsigned char *up = (unsigned char *)u;
// load ut with the first 64 bits of the UUID
ut = ((uint64_t)ntohl(*((uint32_t*)up))) << 32;
ut |= ((uint64_t)ntohl(*((uint32_t*)&up[4])));
// dance the bit-shift...
ut =
((ut >> 32) & 0x0FFF) | // 12 least significant bits
(0x6000) | // version number
((ut >> 28) & 0x0000000FFFFF0000) | // next 20 bits
((ut << 20) & 0x000FFFF000000000) | // next 16 bits
(ut << 52); // 12 most significant bits
// store back in UUID
*((uint32_t*)up) = htonl((uint32_t)(ut >> 32));
*((uint32_t*)&up[4]) = htonl((uint32_t)(ut));
}
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
// ...
// csprng data source
FILE *rndf;
rndf = fopen("/dev/urandom", "r");
if (rndf == 0) {
printf("fopen /dev/urandom error\n");
return 1;
}
// ...
// generate one UUIDv7E
uint8_t u[16];
struct timespec ts;
int ret;
ret = clock_gettime(CLOCK_REALTIME, &ts);
if (ret != 0) {
printf("clock_gettime error: %d\n", ret);
return 1;
}
uint64_t tms;
tms = ((uint64_t)ts.tv_sec) * 1000;
tms += ((uint64_t)ts.tv_nsec) / 1000000;
memset(u, 0, 16);
fread(&u[6], 10, 1, rndf); // fill everything after the timestamp with random bytes
*((uint64_t*)(u)) |= htonll(tms << 16); // shift time into first 48 bits and OR into place
u[8] = 0x80 | (u[8] & 0x3F); // set variant field, top two bits are 1, 0
u[6] = 0x70 | (u[6] & 0x0F); // set version field, top four bits are 0, 1, 1, 1
UUIDv8 will vary greatly from implementation to implementation. A good candidate use case for UUIDv8 is to embed exotic timestamps like the one found in this example which employs approximately 0.25 milliseconds and approximately 5 microseconds per timestamp tick as a 48 bit value.¶
#include <stdint.h>
#include <stdio.h>
#include <time.h>
int main() {
struct timespec tp;
clock_gettime(CLOCK_REALTIME, &tp);
uint64_t timestamp = (uint64_t)tp.tv_sec << 12;
// compute 12 bit (~0.25 msec precision) fraction from nsecs
timestamp |= ((uint64_t)tp.tv_nsec << 12) / 1000000000;
printf("%08llx-%04llx\n", timestamp >> 16, timestamp & 0xFFFF);
return 0;
}
Both UUIDv1 and UUIDv6 test vectors utilize the same 60 bit timestamp: 0x1EC9414C232AB00 (138648505420000000) Tuesday, February 22, 2022 2:22:22.000000 PM GMT-05:00¶
Both UUIDv1 and UUIDv6 utilize the same values in clk_seq_hi_res, clock_seq_low, and node. All of which have been generated with random data.¶
# Unix Nanosecond precision to Gregorian 100-nanosecond intervals gregorian_100_ns = (Unix_64_bit_nanoseconds / 100) + gregorian_Unix_offset # 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. # gregorian_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_nanoseconds = 0x16D6320C3D4DCC00 or 1645557742000000000 # Work: # gregorian_100_ns = (1645557742000000000 / 100) + 122192928000000000 # (138648505420000000 - 122192928000000000) * 100 = Unix_64_bit_nanoseconds # Final: # gregorian_100_ns = 0x1EC9414C232AB00 or 138648505420000000 # Original: 000111101100100101000001010011000010001100101010101100000000 # UUIDv1: 11000010001100101010101100000000|1001010000010100|0001|000111101100 # UUIDv6: 00011110110010010100000101001100|0010001100101010|0110|101100000000
---------------------------------------------- field bits value_hex ---------------------------------------------- time_low 32 0xC232AB00 time_mid 16 0x9414 time_hi_and_version 16 0x11EC clk_seq_hi_res 8 0xB3 clock_seq_low 8 0xC8 node 48 0x9E6BDECED846 ---------------------------------------------- total 128 ---------------------------------------------- final_hex: C232AB00-9414-11EC-B3C8-9E6BDECED846
----------------------------------------------- field bits value_hex ----------------------------------------------- time_high 32 0x1EC9414C time_mid 16 0x232A time_low_and_version 16 0x6B00 clk_seq_hi_res 8 0xB3 clock_seq_low 8 0xC8 node 48 0x9E6BDECED846 ----------------------------------------------- total 128 ----------------------------------------------- final_hex: 1EC9414C-232A-6B00-B3C8-9E6BDECED846
This example UUIDv7 test vector utilizes a well-known 32 bit Unix epoch with additional millisecond precision to fill the first 48 bits¶
rand_a and rand_b are filled with random data.¶
The timestamp is Tuesday, February 22, 2022 2:22:22.00 PM GMT-05:00 represented as 0x17F21CFD130 or 1645539742000¶
------------------------------- field bits value ------------------------------- unix_ts_ms 48 0x017F21CFD130 var 4 0x7 rand_a 12 0xCC3 var 2 b10 rand_b 62 0x18C4DC0C0C07398F ------------------------------- total 128 ------------------------------- final: 017F21CF-D130-7CC3-98C4-DC0C0C07398F
This example UUIDv8 test vector utilizes a well-known 64 bit Unix epoch with nanosecond precision, truncated to the least-significant, right-most, bits to fill the first 48 bits through version.¶
The next two segments of custom_b and custom_c are are filled with random data.¶
Timestamp is Tuesday, February 22, 2022 2:22:22.000000 PM GMT-05:00 represented as 0x16D6320C3D4DCC00 or 1645557742000000000¶
It should be noted that this example is just to illustrate one scenario for UUIDv8. Test vectors will likely be implementation specific and vary greatly from this simple example.¶
------------------------------- field bits value ------------------------------- custom_a 48 0x320C3D4DCC00 ver 4 0x8 custom_b 12 0x75B var 2 b10 custom_c 62 0xEC932D5F69181C0 ------------------------------- total 128 ------------------------------- final: 320C3D4D-CC00-875B-8EC9-32D5F69181C0
| Msb0 | Msb1 | Msb2 | Msb3 | Version | Description |
| 0 | 0 | 0 | 0 | 0 | Unused |
| 0 | 0 | 0 | 1 | 1 | The Gregorian time-based UUID from in [RFC4122], Section 4.1.3 |
| 0 | 0 | 1 | 0 | 2 | DCE Security version, with embedded POSIX UIDs from [RFC4122], Section 4.1.3 |
| 0 | 0 | 1 | 1 | 3 | The name-based version specified in [RFC4122], Section 4.1.3 that uses MD5 hashing. |
| 0 | 1 | 0 | 0 | 4 | The randomly or pseudo-randomly generated version specified in [RFC4122], Section 4.1.3. |
| 0 | 1 | 0 | 1 | 5 | The name-based version specified in [RFC4122], Section 4.1.3 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. |
| Msb0 | Msb1 | Msb2 | Msb3 | Version | Description |
| 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 |
| Msb0 | Msb1 | Msb2 | Msb3 | Version | Description |
| 0 | 0 | 0 | 0 | 0 | Unused |
| 0 | 0 | 0 | 1 | 1 | The Gregorian time-based UUID from in |
| 0 | 0 | 1 | 0 | 2 | DCE Security version, with embedded POSIX UIDs from |
| 0 | 0 | 1 | 1 | 3 | The name-based version specified in |
| 0 | 1 | 0 | 0 | 4 | The randomly or pseudo-randomly generated version specified in |
| 0 | 1 | 0 | 1 | 5 | The name-based version specified in |
| 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. |