├── .circleci
└── config.yml
├── .editorconfig
├── .github
├── CODEOWNERS
└── workflows
│ ├── archive.yml
│ ├── ghpages.yml
│ ├── publish.yml
│ └── update.yml
├── .gitignore
├── .note.xml
├── CONTRIBUTING.md
├── LICENSE.md
├── Makefile
├── README.md
├── docs
├── better-rfc.css
├── draft-00
│ ├── draft-ietf-uuidrev-rfc4122bis.html
│ └── draft-ietf-uuidrev-rfc4122bis.txt
├── draft-01
│ ├── draft-ietf-uuidrev-rfc4122bis.html
│ └── draft-ietf-uuidrev-rfc4122bis.txt
└── draft-03
│ ├── draft-ietf-uuidrev-rfc4122bis.html
│ └── draft-ietf-uuidrev-rfc4122bis.txt
├── draft-ietf-uuidrev-rfc4122bis.md
└── editor-files
├── UUIDv3-v5-Testing.md
├── draft-peabody-dispatch-new-uuid-format-04.md
├── rfc4122bis.md
└── sed-css-replace.md
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | build:
4 | docker:
5 | - image: martinthomson/i-d-template:latest
6 | resource_class: small
7 | working_directory: ~/draft
8 |
9 | steps:
10 | - run:
11 | name: "Print Configuration"
12 | command: |
13 | xml2rfc --version
14 | gem list -q kramdown-rfc
15 | echo -n 'mmark '; mmark --version
16 |
17 | - restore_cache:
18 | name: "Restoring cache - Git"
19 | keys:
20 | - v2-cache-git-{{ .Branch }}-{{ .Revision }}
21 | - v2-cache-git-{{ .Branch }}
22 | - v2-cache-git-
23 |
24 | - restore_cache:
25 | name: "Restoring cache - References"
26 | keys:
27 | - v1-cache-references-{{ epoch }}
28 | - v1-cache-references-
29 |
30 | # Workaround for https://discuss.circleci.com/t/22437
31 | - run:
32 | name: Tag Checkout
33 | command: |
34 | if [ -n "$CIRCLE_TAG" ] && [ -d .git ]; then
35 | remote=$(echo "$CIRCLE_REPOSITORY_URL" | \
36 | sed -e 's,/^git.github.com:,https://github.com/,')
37 | git fetch -f "$remote" "refs/tags/$CIRCLE_TAG:refs/tags/$CIRCLE_TAG" || \
38 | (echo 'Removing .git cache for tag build'; rm -rf .git)
39 | fi
40 |
41 | - checkout
42 |
43 | # Build txt and html versions of drafts
44 | - run:
45 | name: "Build Drafts"
46 | command: make
47 |
48 | # Update editor's copy on gh-pages
49 | - run:
50 | name: "Update GitHub Pages"
51 | command: |
52 | if [ "${CIRCLE_TAG#draft-}" == "$CIRCLE_TAG" ]; then
53 | make gh-pages
54 | fi
55 |
56 | # For tagged builds, upload to the datatracker.
57 | - deploy:
58 | name: "Upload to Datatracker"
59 | command: |
60 | if [ "${CIRCLE_TAG#draft-}" != "$CIRCLE_TAG" ]; then
61 | make upload
62 | fi
63 |
64 | # Archive GitHub Issues
65 | - run:
66 | name: "Archive GitHub Issues"
67 | command: "make archive || make archive DISABLE_ARCHIVE_FETCH=true && make gh-archive"
68 |
69 | # Create and store artifacts
70 | - run:
71 | name: "Create Artifacts"
72 | command: "make artifacts CI_ARTIFACTS=/tmp/artifacts"
73 |
74 | - store_artifacts:
75 | path: /tmp/artifacts
76 |
77 | - run:
78 | name: "Prepare for Caching"
79 | command: "git reflog expire --expire=now --all && git gc --prune=now"
80 |
81 | - save_cache:
82 | name: "Saving Cache - Git"
83 | key: v2-cache-git-{{ .Branch }}-{{ .Revision }}
84 | paths:
85 | - ~/draft/.git
86 |
87 | - save_cache:
88 | name: "Saving Cache - Drafts"
89 | key: v1-cache-references-{{ epoch }}
90 | paths:
91 | - ~/.cache/xml2rfc
92 |
93 |
94 | workflows:
95 | version: 2
96 | build:
97 | jobs:
98 | - build:
99 | filters:
100 | tags:
101 | only: /.*?/
102 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # See http://editorconfig.org
2 |
3 | root = true
4 |
5 | [*.{md,xml,org}]
6 | charset = utf-8
7 | insert_final_newline = true
8 | trim_trailing_whitespace = true
9 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Automatically generated CODEOWNERS
2 | # Regenerate with `make update-codeowners`
3 | draft-ietf-uuidrev-rfc4122bis.md
4 |
--------------------------------------------------------------------------------
/.github/workflows/archive.yml:
--------------------------------------------------------------------------------
1 | name: "Archive Issues and Pull Requests"
2 |
3 | on:
4 | schedule:
5 | - cron: '0 0 * * 0,2,4'
6 | repository_dispatch:
7 | types: [archive]
8 | workflow_dispatch:
9 |
10 | jobs:
11 | build:
12 | name: "Archive Issues and Pull Requests"
13 | runs-on: ubuntu-latest
14 | steps:
15 | - name: "Checkout"
16 | uses: actions/checkout@v2
17 |
18 | # Note: No caching for this build!
19 |
20 | - name: "Update Archive"
21 | uses: martinthomson/i-d-template@v1
22 | with:
23 | make: archive
24 | token: ${{ github.token }}
25 |
26 | - name: "Update GitHub Pages"
27 | uses: martinthomson/i-d-template@v1
28 | with:
29 | make: gh-archive
30 | token: ${{ github.token }}
31 |
32 | - name: "Save Archive"
33 | uses: actions/upload-artifact@v2
34 | with:
35 | path: archive.json
36 |
--------------------------------------------------------------------------------
/.github/workflows/ghpages.yml:
--------------------------------------------------------------------------------
1 | name: "Update Editor's Copy"
2 |
3 | on:
4 | push:
5 | paths-ignore:
6 | - README.md
7 | - CONTRIBUTING.md
8 | - LICENSE.md
9 | - .gitignore
10 | pull_request:
11 | paths-ignore:
12 | - README.md
13 | - CONTRIBUTING.md
14 | - LICENSE.md
15 | - .gitignore
16 |
17 | jobs:
18 | build:
19 | name: "Update Editor's Copy"
20 | runs-on: ubuntu-latest
21 | steps:
22 | - name: "Checkout"
23 | uses: actions/checkout@v3
24 |
25 | - name: "Setup"
26 | id: setup
27 | run: date -u "+::set-output name=date::%FT%T"
28 |
29 | - name: "Caching"
30 | uses: actions/cache@v3
31 | with:
32 | path: |
33 | .refcache
34 | .venv
35 | .gems
36 | node_modules
37 | .targets.mk
38 | key: i-d-${{ steps.setup.outputs.date }}
39 | restore-keys: i-d-
40 |
41 | - name: "Build Drafts"
42 | uses: martinthomson/i-d-template@v1
43 | with:
44 | token: ${{ github.token }}
45 |
46 | - name: "Update GitHub Pages"
47 | uses: martinthomson/i-d-template@v1
48 | if: ${{ github.event_name == 'push' }}
49 | with:
50 | make: gh-pages
51 | token: ${{ github.token }}
52 |
53 | - name: "Archive Built Drafts"
54 | uses: actions/upload-artifact@v2
55 | with:
56 | path: |
57 | draft-*.html
58 | draft-*.txt
59 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: "Publish New Draft Version"
2 |
3 | on:
4 | push:
5 | tags:
6 | - "draft-*"
7 |
8 | jobs:
9 | build:
10 | name: "Publish New Draft Version"
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: "Checkout"
14 | uses: actions/checkout@v3
15 |
16 | # See https://github.com/actions/checkout/issues/290
17 | - name: "Get Tag Annotations"
18 | run: git fetch -f origin ${{ github.ref }}:${{ github.ref }}
19 |
20 | - name: "Setup"
21 | id: setup
22 | run: date -u "+::set-output name=date::%FT%T"
23 |
24 | - name: "Caching"
25 | uses: actions/cache@v3
26 | with:
27 | path: |
28 | .refcache
29 | .venv
30 | .gems
31 | node_modules
32 | .targets.mk
33 | key: i-d-${{ steps.setup.outputs.date }}
34 | restore-keys: i-d-
35 |
36 | - name: "Build Drafts"
37 | uses: martinthomson/i-d-template@v1
38 | with:
39 | token: ${{ github.token }}
40 |
41 | - name: "Upload to Datatracker"
42 | uses: martinthomson/i-d-template@v1
43 | with:
44 | make: upload
45 |
46 | - name: "Archive Submitted Drafts"
47 | uses: actions/upload-artifact@v2
48 | with:
49 | path: "draft-*-[0-9][0-9].xml"
50 |
--------------------------------------------------------------------------------
/.github/workflows/update.yml:
--------------------------------------------------------------------------------
1 | name: "Update Generated Files"
2 | # This rule is not run automatically.
3 | # It can be run manually to update all of the files that are part
4 | # of the template, specifically:
5 | # - README.md
6 | # - CONTRIBUTING.md
7 | # - .note.xml
8 | # - .github/CODEOWNERS
9 | # - Makefile
10 | #
11 | #
12 | # This might be useful if you have:
13 | # - added, removed, or renamed drafts (including after adoption)
14 | # - added, removed, or changed draft editors
15 | # - changed the title of drafts
16 | #
17 | # Note that this removes any customizations you have made to
18 | # the affected files.
19 | on: workflow_dispatch
20 |
21 | jobs:
22 | build:
23 | name: "Update Files"
24 | runs-on: ubuntu-latest
25 | steps:
26 | - name: "Checkout"
27 | uses: actions/checkout@v2
28 |
29 | - name: "Update Generated Files"
30 | uses: martinthomson/i-d-template@v1
31 | with:
32 | make: update-files
33 | token: ${{ github.token }}
34 |
35 | - name: "Push Update"
36 | run: git push
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /*.html
2 | *.pdf
3 | *.redxml
4 | *.swp
5 | /*.txt
6 | *.upload
7 | *~
8 | .tags
9 | /*-[0-9][0-9].xml
10 | /.gems/
11 | /.refcache
12 | /.targets.mk
13 | /.venv/
14 | /.vscode/
15 | /lib
16 | /node_modules/
17 | /versioned/
18 | Gemfile.lock
19 | archive.json
20 | draft-ietf-uuidrev-rfc4122bis.xml
21 | package-lock.json
22 | report.xml
23 | !requirements.txt
24 | !docs/*
25 | !docs/*
26 |
27 |
--------------------------------------------------------------------------------
/.note.xml:
--------------------------------------------------------------------------------
1 |
2 | Discussion of this document takes place on the
3 | Revise Universally Unique Identifier Definitions Working Group mailing list (uuidrev@ietf.org),
4 | which is archived at .
5 | Source for this draft and an issue tracker can be found at
6 | .
7 |
8 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | This repository relates to activities in the Internet Engineering Task Force
4 | ([IETF](https://www.ietf.org/)). All material in this repository is considered
5 | Contributions to the IETF Standards Process, as defined in the intellectual
6 | property policies of IETF currently designated as
7 | [BCP 78](https://www.rfc-editor.org/info/bcp78),
8 | [BCP 79](https://www.rfc-editor.org/info/bcp79) and the
9 | [IETF Trust Legal Provisions (TLP) Relating to IETF Documents](http://trustee.ietf.org/trust-legal-provisions.html).
10 |
11 | Any edit, commit, pull request, issue, comment or other change made to this
12 | repository constitutes Contributions to the IETF Standards Process
13 | (https://www.ietf.org/).
14 |
15 | You agree to comply with all applicable IETF policies and procedures, including,
16 | BCP 78, 79, the TLP, and the TLP rules regarding code components (e.g. being
17 | subject to a Simplified BSD License) in Contributions.
18 |
19 | ## Working Group Information
20 |
21 | Discussion of this work occurs on the [Revise Universally Unique Identifier Definitions
22 | Working Group mailing list](mailto:uuidrev@ietf.org)
23 | ([archive](https://mailarchive.ietf.org/arch/browse/uuidrev/),
24 | [subscribe](https://www.ietf.org/mailman/listinfo/uuidrev)).
25 | In addition to contributions in GitHub, you are encouraged to participate in
26 | discussions there.
27 |
28 | **Note**: Some working groups adopt a policy whereby substantive discussion of
29 | technical issues needs to occur on the mailing list.
30 |
31 | You might also like to familiarize yourself with other
32 | [Working Group documents](https://datatracker.ietf.org/wg/uuidrev/documents/).
33 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # License
2 |
3 | See the
4 | [guidelines for contributions](https://github.com/ietf-wg-uuidrev/rfc4122bis/blob/main/CONTRIBUTING.md).
5 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | LIBDIR := lib
2 | include $(LIBDIR)/main.mk
3 |
4 | $(LIBDIR)/main.mk:
5 | ifneq (,$(shell grep "path *= *$(LIBDIR)" .gitmodules 2>/dev/null))
6 | git submodule sync
7 | git submodule update $(CLONE_ARGS) --init
8 | else
9 | git clone -q --depth 10 $(CLONE_ARGS) \
10 | -b main https://github.com/martinthomson/i-d-template $(LIBDIR)
11 | endif
12 |
13 |
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Universally Unique IDentifiers (UUID)
2 |
3 | This is the working area for the IETF [UUIDREV Working Group](https://datatracker.ietf.org/wg/uuidrev/documents/) Internet-Draft, "A Universally Unique IDentifier (UUID) URN Namespace".
4 |
5 | * [Datatracker Page](https://datatracker.ietf.org/doc/draft-ietf-uuidrev-rfc4122bis)
6 | * [Working Group Draft](https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis)
7 | * [Prototypes](https://github.com/uuid6/prototypes)
8 |
9 | # Latest
10 | ```
11 | RFC 9562
12 |
13 | Title: Universally Unique IDentifiers (UUIDs)
14 | Author: K. Davis,
15 | B. Peabody,
16 | P. Leach
17 | Status: Standards Track
18 | Stream: IETF
19 | Date: May 2024
20 | Mailbox: kydavis@cisco.com,
21 | brad@peabody.io,
22 | pjl7@uw.edu
23 | Pages: 46
24 | Obsoletes: RFC 4122
25 |
26 | I-D Tag: draft-ietf-uuidrev-rfc4122bis-14.txt
27 |
28 | URL: https://www.rfc-editor.org/info/rfc9562
29 |
30 | DOI: 10.17487/RFC9562
31 |
32 | ```
33 |
34 | ## Contributing
35 |
36 | See the
37 | [guidelines for contributions](https://github.com/ietf-wg-uuidrev/rfc4122bis/blob/main/CONTRIBUTING.md).
38 |
39 | Contributions can be made by creating pull requests.
40 | The GitHub interface supports creating pull requests using the Edit (✏) button.
41 |
42 |
43 | ## Command Line Usage
44 |
45 | Formatted text and HTML versions of the draft can be built using `make`.
46 |
47 | ```sh
48 | $ make
49 | ```
50 |
51 | Command line usage requires that you have the necessary software installed. See
52 | [the instructions](https://github.com/martinthomson/i-d-template/blob/main/doc/SETUP.md).
53 |
54 |
--------------------------------------------------------------------------------
/docs/better-rfc.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | NOTE: Changes at the bottom of this file overrides some earlier settings.
4 |
5 | Once the style has stabilized and has been adopted as an official RFC style,
6 | this can be consolidated so that style settings occur only in one place, but
7 | for now the contents of this file consists first of the initial CSS work as
8 | provided to the RFC Formatter (xml2rfc) work, followed by itemized and
9 | commented changes found necssary during the development of the v3
10 | formatters.
11 |
12 | */
13 |
14 | /* fonts */
15 | @import url('https://fonts.googleapis.com/css?family=Noto+Sans'); /* Sans-serif */
16 | @import url('https://fonts.googleapis.com/css?family=Noto+Serif'); /* Serif (print) */
17 | @import url('https://fonts.googleapis.com/css?family=Roboto+Mono'); /* Monospace */
18 |
19 | @viewport {
20 | zoom: 1.0;
21 | width: extend-to-zoom;
22 | }
23 | @-ms-viewport {
24 | width: extend-to-zoom;
25 | zoom: 1.0;
26 | }
27 | /* general and mobile first */
28 | html {
29 | }
30 | body {
31 | max-width: 90%;
32 | margin: 1.5em auto;
33 | color: #222;
34 | background-color: #fff;
35 | font-size: 14px;
36 | font-family: 'Noto Sans', Arial, Helvetica, sans-serif;
37 | line-height: 1.6;
38 | scroll-behavior: smooth;
39 | }
40 | .ears {
41 | display: none;
42 | }
43 |
44 | /* headings */
45 | #title, h1, h2, h3, h4, h5, h6 {
46 | margin: 1em 0 0.5em;
47 | font-weight: bold;
48 | line-height: 1.3;
49 | }
50 | #title {
51 | clear: both;
52 | border-bottom: 1px solid #ddd;
53 | margin: 0 0 0.5em 0;
54 | padding: 1em 0 0.5em;
55 | }
56 | .author {
57 | padding-bottom: 4px;
58 | }
59 | h1 {
60 | font-size: 26px;
61 | margin: 1em 0;
62 | }
63 | h2 {
64 | font-size: 22px;
65 | margin-top: -20px; /* provide offset for in-page anchors */
66 | padding-top: 33px;
67 | }
68 | h3 {
69 | font-size: 18px;
70 | margin-top: -36px; /* provide offset for in-page anchors */
71 | padding-top: 42px;
72 | }
73 | h4 {
74 | font-size: 16px;
75 | margin-top: -36px; /* provide offset for in-page anchors */
76 | padding-top: 42px;
77 | }
78 | h5, h6 {
79 | font-size: 14px;
80 | }
81 | #n-copyright-notice {
82 | border-bottom: 1px solid #ddd;
83 | padding-bottom: 1em;
84 | margin-bottom: 1em;
85 | }
86 | /* general structure */
87 | p {
88 | padding: 0;
89 | margin: 0 0 1em 0;
90 | text-align: left;
91 | }
92 | div, span {
93 | position: relative;
94 | }
95 | div {
96 | margin: 0;
97 | }
98 | .alignRight.art-text {
99 | background-color: #f9f9f9;
100 | border: 1px solid #eee;
101 | border-radius: 3px;
102 | padding: 1em 1em 0;
103 | margin-bottom: 1.5em;
104 | }
105 | .alignRight.art-text pre {
106 | padding: 0;
107 | }
108 | .alignRight {
109 | margin: 1em 0;
110 | }
111 | .alignRight > *:first-child {
112 | border: none;
113 | margin: 0;
114 | float: right;
115 | clear: both;
116 | }
117 | .alignRight > *:nth-child(2) {
118 | clear: both;
119 | display: block;
120 | border: none;
121 | }
122 | svg {
123 | display: block;
124 | }
125 | .alignCenter.art-text {
126 | background-color: #f9f9f9;
127 | border: 1px solid #eee;
128 | border-radius: 3px;
129 | padding: 1em 1em 0;
130 | margin-bottom: 1.5em;
131 | }
132 | .alignCenter.art-text pre {
133 | padding: 0;
134 | }
135 | .alignCenter {
136 | margin: 1em 0;
137 | }
138 | .alignCenter > *:first-child {
139 | border: none;
140 | margin: 0 auto;
141 | }
142 |
143 | /* lists */
144 | ol, ul {
145 | padding: 0;
146 | margin: 0 0 1em 2em;
147 | }
148 | ol ol, ul ul, ol ul, ul ol {
149 | margin-left: 1em;
150 | }
151 | li {
152 | margin: 0 0 0.25em 0;
153 | }
154 | .ulCompact li {
155 | margin: 0;
156 | }
157 | ul.empty, .ulEmpty {
158 | list-style-type: none;
159 | }
160 | ul.empty li, .ulEmpty li {
161 | margin-top: 0.5em;
162 | }
163 | ul.ulBare, li.ulBare {
164 | margin-left: 0em !important;
165 | }
166 | ul.compact, .ulCompact,
167 | ol.compact, .olCompact {
168 | line-height: 100%;
169 | margin: 0 0 0 2em;
170 | }
171 |
172 | /* definition lists */
173 | dl {
174 | }
175 | dl > dt {
176 | float: left;
177 | margin-right: 1em;
178 | }
179 | /*
180 | dl.nohang > dt {
181 | float: none;
182 | }
183 | */
184 | dl > dd {
185 | margin-bottom: .8em;
186 | min-height: 1.3em;
187 | }
188 | dl.compact > dd, .dlCompact > dd {
189 | margin-bottom: 0em;
190 | }
191 | dl > dd > dl {
192 | margin-top: 0.5em;
193 | margin-bottom: 0em;
194 | }
195 |
196 | /* links */
197 | a {
198 | text-decoration: none;
199 | }
200 | a[href] {
201 | color: #22e; /* Arlen: WCAG 2019 */
202 | }
203 | a[href]:hover {
204 | background-color: #f2f2f2;
205 | }
206 | figcaption a[href],
207 | a[href].selfRef {
208 | color: #222;
209 | }
210 | /* XXX probably not this:
211 | a.selfRef:hover {
212 | background-color: transparent;
213 | cursor: default;
214 | } */
215 |
216 | /* Figures */
217 | tt, code, pre, code {
218 | background-color: #f9f9f9;
219 | font-family: 'Roboto Mono', monospace;
220 | }
221 | pre {
222 | border: 1px solid #eee;
223 | margin: 0;
224 | padding: 1em;
225 | }
226 | img {
227 | max-width: 100%;
228 | }
229 | figure {
230 | margin: 0;
231 | }
232 | figure blockquote {
233 | margin: 0.8em 0.4em 0.4em;
234 | }
235 | figcaption {
236 | font-style: italic;
237 | margin: 0 0 1em 0;
238 | }
239 | @media screen {
240 | pre {
241 | overflow-x: auto;
242 | max-width: 100%;
243 | max-width: calc(100% - 22px);
244 | }
245 | }
246 |
247 | /* aside, blockquote */
248 | aside, blockquote {
249 | margin-left: 0;
250 | padding: 1.2em 2em;
251 | }
252 | blockquote {
253 | background-color: #f9f9f9;
254 | color: #111; /* Arlen: WCAG 2019 */
255 | border: 1px solid #ddd;
256 | border-radius: 3px;
257 | margin: 1em 0;
258 | }
259 | cite {
260 | display: block;
261 | text-align: right;
262 | font-style: italic;
263 | }
264 |
265 | /* tables */
266 | table {
267 | width: 100%;
268 | margin: 0 0 1em;
269 | border-collapse: collapse;
270 | border: 1px solid #eee;
271 | }
272 | th, td {
273 | text-align: left;
274 | vertical-align: top;
275 | padding: 0.5em 0.75em;
276 | }
277 | th {
278 | text-align: left;
279 | background-color: #e9e9e9;
280 | }
281 | tr:nth-child(2n+1) > td {
282 | background-color: #f5f5f5;
283 | }
284 | table caption {
285 | font-style: italic;
286 | margin: 0;
287 | padding: 0;
288 | text-align: left;
289 | }
290 | table p {
291 | /* XXX to avoid bottom margin on table row signifiers. If paragraphs should
292 | be allowed within tables more generally, it would be far better to select on a class. */
293 | margin: 0;
294 | }
295 |
296 | /* pilcrow */
297 | a.pilcrow {
298 | color: #666; /* Arlen: AHDJ 2019 */
299 | text-decoration: none;
300 | visibility: hidden;
301 | user-select: none;
302 | -ms-user-select: none;
303 | -o-user-select:none;
304 | -moz-user-select: none;
305 | -khtml-user-select: none;
306 | -webkit-user-select: none;
307 | -webkit-touch-callout: none;
308 | }
309 | @media screen {
310 | aside:hover > a.pilcrow,
311 | p:hover > a.pilcrow,
312 | blockquote:hover > a.pilcrow,
313 | div:hover > a.pilcrow,
314 | li:hover > a.pilcrow,
315 | pre:hover > a.pilcrow {
316 | visibility: visible;
317 | }
318 | a.pilcrow:hover {
319 | background-color: transparent;
320 | }
321 | }
322 |
323 | /* misc */
324 | hr {
325 | border: 0;
326 | border-top: 1px solid #eee;
327 | }
328 | .bcp14 {
329 | font-variant: small-caps;
330 | }
331 |
332 | .role {
333 | font-variant: all-small-caps;
334 | }
335 |
336 | /* info block */
337 | #identifiers {
338 | margin: 0;
339 | font-size: 0.9em;
340 | }
341 | #identifiers dt {
342 | width: 3em;
343 | clear: left;
344 | }
345 | #identifiers dd {
346 | float: left;
347 | margin-bottom: 0;
348 | }
349 | /* Fix PDF info block run off issue */
350 | @media print {
351 | #identifiers dd {
352 | float: none;
353 | }
354 | }
355 | #identifiers .authors .author {
356 | display: inline-block;
357 | margin-right: 1.5em;
358 | }
359 | #identifiers .authors .org {
360 | font-style: italic;
361 | }
362 |
363 | /* The prepared/rendered info at the very bottom of the page */
364 | .docInfo {
365 | color: #666; /* Arlen: WCAG 2019 */
366 | font-size: 0.9em;
367 | font-style: italic;
368 | margin-top: 2em;
369 | }
370 | .docInfo .prepared {
371 | float: left;
372 | }
373 | .docInfo .prepared {
374 | float: right;
375 | }
376 |
377 | /* table of contents */
378 | #toc {
379 | padding: 0.75em 0 2em 0;
380 | margin-bottom: 1em;
381 | }
382 | nav.toc ul {
383 | margin: 0 0.5em 0 0;
384 | padding: 0;
385 | list-style: none;
386 | }
387 | nav.toc li {
388 | line-height: 1.3em;
389 | margin: 0.75em 0;
390 | padding-left: 1.2em;
391 | text-indent: -1.2em;
392 | }
393 | /* references */
394 | .references dt {
395 | text-align: right;
396 | font-weight: bold;
397 | min-width: 7em;
398 | }
399 | .references dd {
400 | margin-left: 8em;
401 | overflow: auto;
402 | }
403 |
404 | .refInstance {
405 | margin-bottom: 1.25em;
406 | }
407 |
408 | .references .ascii {
409 | margin-bottom: 0.25em;
410 | }
411 |
412 | /* index */
413 | .index ul {
414 | margin: 0 0 0 1em;
415 | padding: 0;
416 | list-style: none;
417 | }
418 | .index ul ul {
419 | margin: 0;
420 | }
421 | .index li {
422 | margin: 0;
423 | text-indent: -2em;
424 | padding-left: 2em;
425 | padding-bottom: 5px;
426 | }
427 | .indexIndex {
428 | margin: 0.5em 0 1em;
429 | }
430 | .index a {
431 | font-weight: 700;
432 | }
433 | /* make the index two-column on all but the smallest screens */
434 | @media (min-width: 600px) {
435 | .index ul {
436 | -moz-column-count: 2;
437 | -moz-column-gap: 20px;
438 | }
439 | .index ul ul {
440 | -moz-column-count: 1;
441 | -moz-column-gap: 0;
442 | }
443 | }
444 |
445 | /* authors */
446 | address.vcard {
447 | font-style: normal;
448 | margin: 1em 0;
449 | }
450 |
451 | address.vcard .nameRole {
452 | font-weight: 700;
453 | margin-left: 0;
454 | }
455 | address.vcard .label {
456 | font-family: "Noto Sans",Arial,Helvetica,sans-serif;
457 | margin: 0.5em 0;
458 | }
459 | address.vcard .type {
460 | display: none;
461 | }
462 | .alternative-contact {
463 | margin: 1.5em 0 1em;
464 | }
465 | hr.addr {
466 | border-top: 1px dashed;
467 | margin: 0;
468 | color: #ddd;
469 | max-width: calc(100% - 16px);
470 | }
471 |
472 | /* temporary notes */
473 | .rfcEditorRemove::before {
474 | position: absolute;
475 | top: 0.2em;
476 | right: 0.2em;
477 | padding: 0.2em;
478 | content: "The RFC Editor will remove this note";
479 | color: #9e2a00; /* Arlen: WCAG 2019 */
480 | background-color: #ffd; /* Arlen: WCAG 2019 */
481 | }
482 | .rfcEditorRemove {
483 | position: relative;
484 | padding-top: 1.8em;
485 | background-color: #ffd; /* Arlen: WCAG 2019 */
486 | border-radius: 3px;
487 | }
488 | .cref {
489 | background-color: #ffd; /* Arlen: WCAG 2019 */
490 | padding: 2px 4px;
491 | }
492 | .crefSource {
493 | font-style: italic;
494 | }
495 | /* alternative layout for smaller screens */
496 | @media screen and (max-width: 1023px) {
497 | body {
498 | padding-top: 2em;
499 | }
500 | #title {
501 | padding: 1em 0;
502 | }
503 | h1 {
504 | font-size: 24px;
505 | }
506 | h2 {
507 | font-size: 20px;
508 | margin-top: -18px; /* provide offset for in-page anchors */
509 | padding-top: 38px;
510 | }
511 | #identifiers dd {
512 | max-width: 60%;
513 | }
514 | #toc {
515 | position: fixed;
516 | z-index: 2;
517 | top: 0;
518 | right: 0;
519 | padding: 0;
520 | margin: 0;
521 | background-color: inherit;
522 | border-bottom: 1px solid #ccc;
523 | }
524 | #toc h2 {
525 | margin: -1px 0 0 0;
526 | padding: 4px 0 4px 6px;
527 | padding-right: 1em;
528 | min-width: 190px;
529 | font-size: 1.1em;
530 | text-align: right;
531 | background-color: #444;
532 | color: white;
533 | cursor: pointer;
534 | }
535 | #toc h2::before { /* css hamburger */
536 | float: right;
537 | position: relative;
538 | width: 1em;
539 | height: 1px;
540 | left: -164px;
541 | margin: 6px 0 0 0;
542 | background: white none repeat scroll 0 0;
543 | box-shadow: 0 4px 0 0 white, 0 8px 0 0 white;
544 | content: "";
545 | }
546 | #toc nav {
547 | display: none;
548 | padding: 0.5em 1em 1em;
549 | overflow: auto;
550 | height: calc(100vh - 48px);
551 | border-left: 1px solid #ddd;
552 | }
553 | }
554 |
555 | /* alternative layout for wide screens */
556 | @media screen and (min-width: 1024px) {
557 | body {
558 | max-width: 724px;
559 | margin: 42px auto;
560 | padding-left: 1.5em;
561 | padding-right: 29em;
562 | }
563 | #toc {
564 | position: fixed;
565 | top: 42px;
566 | right: 42px;
567 | width: 25%;
568 | margin: 0;
569 | padding: 0 1em;
570 | z-index: 1;
571 | }
572 | #toc h2 {
573 | border-top: none;
574 | border-bottom: 1px solid #ddd;
575 | font-size: 1em;
576 | font-weight: normal;
577 | margin: 0;
578 | padding: 0.25em 1em 1em 0;
579 | }
580 | #toc nav {
581 | display: block;
582 | height: calc(90vh - 84px);
583 | bottom: 0;
584 | padding: 0.5em 0 0;
585 | overflow: auto;
586 | }
587 | img { /* future proofing */
588 | max-width: 100%;
589 | height: auto;
590 | }
591 | }
592 |
593 | /* pagination */
594 | @media print {
595 | body {
596 |
597 | width: 100%;
598 | }
599 | p {
600 | orphans: 3;
601 | widows: 3;
602 | }
603 | #n-copyright-notice {
604 | border-bottom: none;
605 | }
606 | #toc, #n-introduction {
607 | page-break-before: always;
608 | }
609 | #toc {
610 | border-top: none;
611 | padding-top: 0;
612 | }
613 | figure, pre {
614 | page-break-inside: avoid;
615 | }
616 | figure {
617 | overflow: scroll;
618 | }
619 | pre.breakable {
620 | break-inside: auto;
621 | }
622 | h1, h2, h3, h4, h5, h6 {
623 | page-break-after: avoid;
624 | }
625 | h2+*, h3+*, h4+*, h5+*, h6+* {
626 | page-break-before: avoid;
627 | }
628 | pre {
629 | white-space: pre-wrap;
630 | word-wrap: break-word;
631 | font-size: 10pt;
632 | }
633 | table {
634 | border: 1px solid #ddd;
635 | }
636 | td {
637 | border-top: 1px solid #ddd;
638 | }
639 | }
640 |
641 | /* This is commented out here, as the string-set: doesn't
642 | pass W3C validation currently */
643 | /*
644 | .ears thead .left {
645 | string-set: ears-top-left content();
646 | }
647 |
648 | .ears thead .center {
649 | string-set: ears-top-center content();
650 | }
651 |
652 | .ears thead .right {
653 | string-set: ears-top-right content();
654 | }
655 |
656 | .ears tfoot .left {
657 | string-set: ears-bottom-left content();
658 | }
659 |
660 | .ears tfoot .center {
661 | string-set: ears-bottom-center content();
662 | }
663 |
664 | .ears tfoot .right {
665 | string-set: ears-bottom-right content();
666 | }
667 | */
668 |
669 | @page :first {
670 | padding-top: 0;
671 | @top-left {
672 | content: normal;
673 | border: none;
674 | }
675 | @top-center {
676 | content: normal;
677 | border: none;
678 | }
679 | @top-right {
680 | content: normal;
681 | border: none;
682 | }
683 | }
684 |
685 | @page {
686 | size: A4;
687 | margin-bottom: 45mm;
688 | padding-top: 20px;
689 | /* The follwing is commented out here, but set appropriately by in code, as
690 | the content depends on the document */
691 | /*
692 | @top-left {
693 | content: 'Internet-Draft';
694 | vertical-align: bottom;
695 | border-bottom: solid 1px #ccc;
696 | }
697 | @top-left {
698 | content: string(ears-top-left);
699 | vertical-align: bottom;
700 | border-bottom: solid 1px #ccc;
701 | }
702 | @top-center {
703 | content: string(ears-top-center);
704 | vertical-align: bottom;
705 | border-bottom: solid 1px #ccc;
706 | }
707 | @top-right {
708 | content: string(ears-top-right);
709 | vertical-align: bottom;
710 | border-bottom: solid 1px #ccc;
711 | }
712 | @bottom-left {
713 | content: string(ears-bottom-left);
714 | vertical-align: top;
715 | border-top: solid 1px #ccc;
716 | }
717 | @bottom-center {
718 | content: string(ears-bottom-center);
719 | vertical-align: top;
720 | border-top: solid 1px #ccc;
721 | }
722 | @bottom-right {
723 | content: '[Page ' counter(page) ']';
724 | vertical-align: top;
725 | border-top: solid 1px #ccc;
726 | }
727 | */
728 |
729 | }
730 |
731 | /* Changes introduced to fix issues found during implementation */
732 | /* Make sure links are clickable even if overlapped by following H* */
733 | a {
734 | z-index: 2;
735 | }
736 | /* Separate body from document info even without intervening H1 */
737 | section {
738 | clear: both;
739 | }
740 |
741 |
742 | /* Top align author divs, to avoid names without organization dropping level with org names */
743 | .author {
744 | vertical-align: top;
745 | }
746 |
747 | /* Leave room in document info to show Internet-Draft on one line */
748 | #identifiers dt {
749 | width: 8em;
750 | }
751 |
752 | /* Don't waste quite as much whitespace between label and value in doc info */
753 | #identifiers dd {
754 | margin-left: 1em;
755 | }
756 |
757 | /* Give floating toc a background color (needed when it's a div inside section */
758 | #toc {
759 | background-color: white;
760 | }
761 |
762 | /* Make the collapsed ToC header render white on gray also when it's a link */
763 | @media screen and (max-width: 1023px) {
764 | #toc h2 a,
765 | #toc h2 a:link,
766 | #toc h2 a:focus,
767 | #toc h2 a:hover,
768 | #toc a.toplink,
769 | #toc a.toplink:hover {
770 | color: white;
771 | background-color: #444;
772 | text-decoration: none;
773 | }
774 | }
775 |
776 | /* Give the bottom of the ToC some whitespace */
777 | @media screen and (min-width: 1024px) {
778 | #toc {
779 | padding: 0 0 1em 1em;
780 | }
781 | }
782 |
783 | /* Style section numbers with more space between number and title */
784 | .section-number {
785 | padding-right: 0.5em;
786 | }
787 |
788 | /* prevent monospace from becoming overly large */
789 | tt, code, pre, code {
790 | font-size: 95%;
791 | }
792 |
793 | /* Fix the height/width aspect for ascii art*/
794 | pre.sourcecode,
795 | .art-text pre {
796 | line-height: 1.12;
797 | }
798 |
799 |
800 | /* Add styling for a link in the ToC that points to the top of the document */
801 | a.toplink {
802 | float: right;
803 | margin-right: 0.5em;
804 | }
805 |
806 | /* Fix the dl styling to match the RFC 7992 attributes */
807 | dl > dt,
808 | dl.dlParallel > dt {
809 | float: left;
810 | margin-right: 1em;
811 | }
812 | dl.dlNewline > dt {
813 | float: none;
814 | }
815 |
816 | /* Provide styling for table cell text alignment */
817 | table td.text-left,
818 | table th.text-left {
819 | text-align: left;
820 | }
821 | table td.text-center,
822 | table th.text-center {
823 | text-align: center;
824 | }
825 | table td.text-right,
826 | table th.text-right {
827 | text-align: right;
828 | }
829 |
830 | /* Make the alternative author contact informatio look less like just another
831 | author, and group it closer with the primary author contact information */
832 | .alternative-contact {
833 | margin: 0.5em 0 0.25em 0;
834 | }
835 | address .non-ascii {
836 | margin: 0 0 0 2em;
837 | }
838 |
839 | /* With it being possible to set tables with alignment
840 | left, center, and right, { width: 100%; } does not make sense */
841 | table {
842 | width: auto;
843 | }
844 |
845 | /* Avoid reference text that sits in a block with very wide left margin,
846 | because of a long floating dt label.*/
847 | .references dd {
848 | overflow: visible;
849 | }
850 |
851 | /* Control caption placement */
852 | caption {
853 | caption-side: bottom;
854 | }
855 |
856 | /* Limit the width of the author address vcard, so names in right-to-left
857 | script don't end up on the other side of the page. */
858 |
859 | address.vcard {
860 | max-width: 30em;
861 | margin-right: auto;
862 | }
863 |
864 | /* For address alignment dependent on LTR or RTL scripts */
865 | address div.left {
866 | text-align: left;
867 | }
868 | address div.right {
869 | text-align: right;
870 | }
871 |
872 | /* Provide table alignment support. We can't use the alignX classes above
873 | since they do unwanted things with caption and other styling. */
874 | table.right {
875 | margin-left: auto;
876 | margin-right: 0;
877 | }
878 | table.center {
879 | margin-left: auto;
880 | margin-right: auto;
881 | }
882 | table.left {
883 | margin-left: 0;
884 | margin-right: auto;
885 | }
886 |
887 | /* Give the table caption label the same styling as the figcaption */
888 | caption a[href] {
889 | color: #222;
890 | }
891 |
892 | @media print {
893 | .toplink {
894 | display: none;
895 | }
896 |
897 | /* avoid overwriting the top border line with the ToC header */
898 | #toc {
899 | padding-top: 1px;
900 | }
901 |
902 | /* Avoid page breaks inside dl and author address entries */
903 | .vcard {
904 | page-break-inside: avoid;
905 | }
906 |
907 | }
908 | /* Tweak the bcp14 keyword presentation */
909 | .bcp14 {
910 | font-variant: small-caps;
911 | font-weight: bold;
912 | font-size: 0.9em;
913 | }
914 | /* Tweak the invisible space above H* in order not to overlay links in text above */
915 | h2 {
916 | margin-top: -18px; /* provide offset for in-page anchors */
917 | padding-top: 31px;
918 | }
919 | h3 {
920 | margin-top: -18px; /* provide offset for in-page anchors */
921 | padding-top: 24px;
922 | }
923 | h4 {
924 | margin-top: -18px; /* provide offset for in-page anchors */
925 | padding-top: 24px;
926 | }
927 | /* Float artwork pilcrow to the right */
928 | @media screen {
929 | .artwork a.pilcrow {
930 | display: block;
931 | line-height: 0.7;
932 | margin-top: 0.15em;
933 | }
934 | }
935 | /* Make pilcrows on dd visible */
936 | @media screen {
937 | dd:hover > a.pilcrow {
938 | visibility: visible;
939 | }
940 | }
941 | /* Make the placement of figcaption match that of a table's caption
942 | by removing the figure's added bottom margin */
943 | .alignLeft.art-text,
944 | .alignCenter.art-text,
945 | .alignRight.art-text {
946 | margin-bottom: 0;
947 | }
948 | .alignLeft,
949 | .alignCenter,
950 | .alignRight {
951 | margin: 1em 0 0 0;
952 | }
953 | /* In print, the pilcrow won't show on hover, so prevent it from taking up space,
954 | possibly even requiring a new line */
955 | @media print {
956 | a.pilcrow {
957 | display: none;
958 | }
959 | }
960 | /* Styling for the external metadata */
961 | div#external-metadata {
962 | background-color: #eee;
963 | padding: 0.5em;
964 | margin-bottom: 0.5em;
965 | display: none;
966 | }
967 | div#internal-metadata {
968 | padding: 0.5em; /* to match the external-metadata padding */
969 | }
970 | /* Styling for title RFC Number */
971 | h1#rfcnum {
972 | clear: both;
973 | margin: 0 0 -1em;
974 | padding: 1em 0 0 0;
975 | }
976 | /* Make .olPercent look the same as
- */
977 | dl.olPercent > dd {
978 | margin-bottom: 0.25em;
979 | min-height: initial;
980 | }
981 | /* Give aside some styling to set it apart */
982 | aside {
983 | border-left: 1px solid #ddd;
984 | margin: 1em 0 1em 2em;
985 | padding: 0.2em 2em;
986 | }
987 | aside > dl,
988 | aside > ol,
989 | aside > ul,
990 | aside > table,
991 | aside > p {
992 | margin-bottom: 0.5em;
993 | }
994 | /* Additional page break settings */
995 | @media print {
996 | figcaption, table caption {
997 | page-break-before: avoid;
998 | }
999 | }
1000 | /* Font size adjustments for print */
1001 | @media print {
1002 | body { font-size: 10pt; line-height: normal; max-width: 96%; }
1003 | h1 { font-size: 1.72em; padding-top: 1.5em; } /* 1*1.2*1.2*1.2 */
1004 | h2 { font-size: 1.44em; padding-top: 1.5em; } /* 1*1.2*1.2 */
1005 | h3 { font-size: 1.2em; padding-top: 1.5em; } /* 1*1.2 */
1006 | h4 { font-size: 1em; padding-top: 1.5em; }
1007 | h5, h6 { font-size: 1em; margin: initial; padding: 0.5em 0 0.3em; }
1008 | }
1009 | /* Sourcecode margin in print, when there's no pilcrow */
1010 | @media print {
1011 | .artwork,
1012 | .sourcecode {
1013 | margin-bottom: 1em;
1014 | }
1015 | }
1016 | /* Avoid narrow tables forcing too narrow table captions, which may render badly */
1017 | table {
1018 | min-width: 20em;
1019 | }
1020 | /* ol type a */
1021 | ol.type-a { list-style-type: lower-alpha; }
1022 | ol.type-A { list-style-type: upper-alpha; }
1023 | ol.type-i { list-style-type: lower-roman; }
1024 | ol.type-I { list-style-type: lower-roman; }
1025 | /* Apply the print table and row borders in general, on request from the RPC,
1026 | and increase the contrast between border and odd row background sligthtly */
1027 | table {
1028 | border: 1px solid #ddd;
1029 | }
1030 | td {
1031 | border-top: 1px solid #ddd;
1032 | }
1033 | tr:nth-child(2n+1) > td {
1034 | background-color: #f8f8f8;
1035 | }
1036 | /* Use style rules to govern display of the TOC. */
1037 | @media screen and (max-width: 1023px) {
1038 | #toc nav { display: none; }
1039 | #toc.active nav { display: block; }
1040 | }
1041 | /* Add support for keepWithNext */
1042 | .keepWithNext {
1043 | break-after: avoid-page;
1044 | break-after: avoid-page;
1045 | }
1046 | /* Add support for keepWithPrevious */
1047 | .keepWithPrevious {
1048 | break-before: avoid-page;
1049 | }
1050 | /* Change the approach to avoiding breaks inside artwork etc. */
1051 | figure, pre, table, .artwork, .sourcecode {
1052 | break-before: auto;
1053 | break-after: auto;
1054 | }
1055 | /* Avoid breaks between
- and
- */
1056 | dl {
1057 | break-before: auto;
1058 | break-inside: auto;
1059 | }
1060 | dt {
1061 | break-before: auto;
1062 | break-after: avoid-page;
1063 | }
1064 | dd {
1065 | break-before: avoid-page;
1066 | break-after: auto;
1067 | orphans: 3;
1068 | widows: 3
1069 | }
1070 | span.break, dd.break {
1071 | margin-bottom: 0;
1072 | min-height: 0;
1073 | break-before: auto;
1074 | break-inside: auto;
1075 | break-after: auto;
1076 | }
1077 | /* Undo break-before ToC */
1078 | @media print {
1079 | #toc {
1080 | break-before: auto;
1081 | }
1082 | }
1083 | /* Text in compact lists should not get extra bottim margin space,
1084 | since that would makes the list not compact */
1085 | ul.compact p, .ulCompact p,
1086 | ol.compact p, .olCompact p {
1087 | margin: 0;
1088 | }
1089 | /* But the list as a whole needs the extra space at the end */
1090 | section ul.compact,
1091 | section .ulCompact,
1092 | section ol.compact,
1093 | section .olCompact {
1094 | margin-bottom: 1em; /* same as p not within ul.compact etc. */
1095 | }
1096 | /* The tt and code background above interferes with for instance table cell
1097 | backgrounds. Changed to something a bit more selective. */
1098 | tt, code {
1099 | background-color: transparent;
1100 | }
1101 | p tt, p code, li tt, li code {
1102 | background-color: #f8f8f8;
1103 | }
1104 | /* Tweak the pre margin -- 0px doesn't come out well */
1105 | pre {
1106 | margin-top: 0.5px;
1107 | }
1108 | /* Tweak the comact list text */
1109 | ul.compact, .ulCompact,
1110 | ol.compact, .olCompact,
1111 | dl.compact, .dlCompact {
1112 | line-height: normal;
1113 | }
1114 | /* Don't add top margin for nested lists */
1115 | li > ul, li > ol, li > dl,
1116 | dd > ul, dd > ol, dd > dl,
1117 | dl > dd > dl {
1118 | margin-top: initial;
1119 | }
1120 | /* Elements that should not be rendered on the same line as a
- */
1121 | /* This should match the element list in writer.text.TextWriter.render_dl() */
1122 | dd > div.artwork:first-child,
1123 | dd > aside:first-child,
1124 | dd > figure:first-child,
1125 | dd > ol:first-child,
1126 | dd > div:first-child > pre.sourcecode,
1127 | dd > table:first-child,
1128 | dd > ul:first-child {
1129 | clear: left;
1130 | }
1131 | /* fix for weird browser behaviour when
is empty */
1132 | dt+dd:empty::before{
1133 | content: "\00a0";
1134 | }
1135 | /* Make paragraph spacing inside - smaller than in body text, to fit better within the list */
1136 | li > p {
1137 | margin-bottom: 0.5em
1138 | }
1139 | /* Don't let p margin spill out from inside list items */
1140 | li > p:last-of-type {
1141 | margin-bottom: 0;
1142 | }
1143 |
--------------------------------------------------------------------------------
/editor-files/UUIDv3-v5-Testing.md:
--------------------------------------------------------------------------------
1 | Some Random notes and reverse engineering and testing various UUIDv3/5 by kydavis@cisco.com
2 |
3 | ### DNS UUID Namespace
4 | `6ba7b810-9dad-11d1-80b4-00c04fd430c8`
5 |
6 | ### DNS UUID Namespace No Dashes
7 | `6ba7b8109dad11d180b400c04fd430c8`
8 |
9 | ### DNS UUID Namespace as Integer
10 | `143098242404177361603877621312831893704`
11 |
12 | ### Example Name
13 | `www.example.com`
14 |
15 | ### Expected v3 MD5 UUID
16 | `5df41881-3aed-3515-88a7-2f4a814cf09e`
17 |
18 | ### v5 SHA1 UUID
19 | `2ed6657d-e927-568b-95e1-2665a8aea6a2`
20 |
21 | ---
22 |
23 | ### Python Byte Conversions
24 | ```python
25 | >>> (143098242404177361603877621312831893704).to_bytes(16, byteorder='big')
26 | b'k\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0O\xd40\xc8'
27 |
28 | >>> bytes("www.example.com", "utf-8")
29 | b'www.example.com'
30 | ```
31 |
32 | ### MD5 in Bash, missing dashes, needs var and ver bits set.
33 | Note Python groups a few together more than 2 hex chars but grouping ever two has the same result
34 | ```bash
35 | kydavis@ubuntu-server:~$ echo -n -e "k\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0O\xd40\xc8www.example.com" | md5sum
36 | 5df418813aed051548a72f4a814cf09e -
37 | ```
38 |
39 | ### SHA1 in Bash, missing dashes, needs var and ver bits set.
40 | ```bash
41 | kydavis@ubuntu-server:~$ echo -n -e "k\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0O\xd40\xc8www.example.com" | sha1sum
42 | 2ed6657de927468b55e12665a8aea6a22dee3e35 -
43 | ```
44 |
45 | ----------------------------
46 |
47 | # Putting all the steps together in Bash
48 | Misc bash commands: `echo`, `sed`, `bc`, `awk`, `md5sum`, `sha1sum`, `sha256sum`
49 |
50 | Purely for understanding the individual steps in greater detail, not super practical
51 |
52 | ### MD5 - 5df41881-3aed-3515-88a7-2f4a814cf09e
53 | ```bash
54 | # Unset vars
55 | unset namespace
56 | unset name
57 | unset namespaceIDoctetString
58 | unset hash
59 | unset variantSpace
60 | unset variant
61 | unset newvVariant
62 |
63 | # Set Vars
64 | namespace=6ba7b810-9dad-11d1-80b4-00c04fd430c8
65 | name=www.example.com
66 |
67 | # Convert Namespace into string of octets
68 | # \x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8
69 | namespaceIDoctetString=$(echo -n $namespace | sed 's/-//g' | sed 's/.\{2\}/\\x&/g')
70 |
71 | # Compute hash
72 | # 5df418813aed051548a72f4a814cf09e
73 | hash=$(echo -n -e $namespaceIDoctetString$name | md5sum)
74 |
75 | # Get the variant hex, convert to uppercase for BC in next step
76 | # 4
77 | variantSpace=$(echo $hash | sed -r 's/^.{16}(.{1}).{15}.*/\1/' | tr '[:lower:]' '[:upper:]')
78 |
79 | # Convert hex to bin ensure always 4 char length and replace upper two chars with 1 and 0
80 | # 1000
81 | variant=$(echo "obase=2; ibase=16; $variantSpace" | bc | awk '{ printf "%04d\n", $0 }' | sed -r 's/.*(..)$/10\1/')
82 |
83 | # convert back to hex
84 | # 8
85 | newVariant=$(echo "obase=16; ibase=2; $variant" | bc)
86 |
87 | # replace Ver (3) and Var, add Dashes, anything remaining is dropped, convert back to lowercase
88 | echo $hash | sed -r 's/^(.{12}).{1}(.{19})/\13\2/' | sed -re "s/(.{8})(.{4}).{1}(.{3}).{1}(.{3})(.{12}).*/\1-\2-3\3-$newVariant\4-\5/" | tr '[:upper:]' '[:lower:]'
89 | # 5df41881-3aed-3515-88a7-2f4a814cf09e
90 | ```
91 |
92 | ### SHA1 - 2ed6657d-e927-568b-95e1-2665a8aea6a2
93 | ```bash
94 | # Unset vars
95 | unset namespace
96 | unset name
97 | unset namespaceIDoctetString
98 | unset hash
99 | unset variantSpace
100 | unset variant
101 | unset newvVariant
102 |
103 | # Set Vars
104 | namespace=6ba7b810-9dad-11d1-80b4-00c04fd430c8
105 | name=www.example.com
106 |
107 | # Convert Namespace into string of octets
108 | # \x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8
109 | namespaceIDoctetString=$(echo -n $namespace | sed 's/-//g' | sed 's/.\{2\}/\\x&/g')
110 |
111 | # Compute hash
112 | # 2ed6657de927468b55e12665a8aea6a22dee3e35
113 | hash=$(echo -n -e $namespaceIDoctetString$name | sha1sum)
114 |
115 | # Get the variant hex, convert to uppercase for BC in next step
116 | # 5
117 | variantSpace=$(echo $hash | sed -r 's/^.{16}(.{1}).{15}.*/\1/' | tr '[:lower:]' '[:upper:]')
118 |
119 | # Convert hex to bin ensure always 4 char length and replace upper two chars with 1 and 0
120 | # 1001
121 | variant=$(echo "obase=2; ibase=16; $variantSpace" | bc | awk '{ printf "%04d\n", $0 }' | sed -r 's/.*(..)$/10\1/')
122 |
123 | # convert back to hex
124 | # 9
125 | newVariant=$(echo "obase=16; ibase=2; $variant" | bc)
126 |
127 | # replace Ver (5) and Var, add Dashes, anything remaining is dropped, convert back to lowercase
128 | echo $hash | sed -r 's/^(.{12}).{1}(.{19})/\13\2/' | sed -re "s/(.{8})(.{4}).{1}(.{3}).{1}(.{3})(.{12}).*/\1-\2-5\3-$newVariant\4-\5/" | tr '[:upper:]' '[:lower:]'
129 | # 2ed6657d-e927-568b-95e1-2665a8aea6a2
130 | ```
131 |
132 | ### SHA256 (Testing a "v8) - 401835fd-a627-870a-873f-ed73f2bc5b2c
133 | ```bash
134 | # Unset vars
135 | unset hashspace
136 | unset namespace
137 | unset name
138 | unset namespaceIDoctetString
139 | unset hash
140 | unset variantSpace
141 | unset variant
142 | unset newvVariant
143 |
144 | # Set Vars
145 | hashspace=3fb32780-953c-4464-9cfd-e85dbbe9843d
146 | namespace=6ba7b810-9dad-11d1-80b4-00c04fd430c8
147 | name=www.example.com
148 |
149 | # Convert Hashspace into string of octets
150 | # \x3f\xb3\x27\x80\x95\x3c\x44\x64\x9c\xfd\xe8\x5d\xbb\xe9\x84\x3d
151 | hashspaceIDoctetString=$(echo -n $hashspace | sed 's/-//g' | sed 's/.\{2\}/\\x&/g')
152 |
153 | # Convert Namespace into string of octets
154 | # \x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8
155 | namespaceIDoctetString=$(echo -n $namespace | sed 's/-//g' | sed 's/.\{2\}/\\x&/g')
156 |
157 | # Compute hash
158 | # 401835fda627a70a073fed73f2bc5b2c2a8936385a38a9c133de0ca4af0dfaed
159 | hash=$(echo -n -e $hashspaceIDoctetString$namespaceIDoctetString$name | sha256sum)
160 |
161 | # Get the variant hex, convert to uppercase for BC in next step
162 | # 0
163 | variantSpace=$(echo $hash | sed -r 's/^.{16}(.{1}).{15}.*/\1/' | tr '[:lower:]' '[:upper:]')
164 |
165 | # Convert hex to bin ensure always 4 char length and replace upper two chars with 1 and 0
166 | # 1000
167 | variant=$(echo "obase=2; ibase=16; $variantSpace" | bc | awk '{ printf "%04d\n", $0 }' | sed -r 's/.*(..)$/10\1/')
168 |
169 | # convert back to hex
170 | # 8
171 | newVariant=$(echo "obase=16; ibase=2; $variant" | bc)
172 |
173 | # replace Ver (8) and Var, add Dashes, anything remaining is dropped, convert back to lowercase
174 | echo $hash | sed -r 's/^(.{12}).{1}(.{19})/\13\2/' | sed -re "s/(.{8})(.{4}).{1}(.{3}).{1}(.{3})(.{12}).*/\1-\2-8\3-$newVariant\4-\5/" | tr '[:upper:]' '[:lower:]'
175 | # 401835fd-a627-870a-873f-ed73f2bc5b2c
176 | ```
177 |
178 | ```python
179 | import hashlib
180 | import uuid
181 |
182 | # predefined by RFC 4122
183 | NAMESPACE_DNS = uuid.UUID("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
184 |
185 | # predefined by new RFC (UUIDv4s I just made up for example)
186 | ALGORITHM_SHA256 = uuid.UUID("3fb32780-953c-4464-9cfd-e85dbbe9843d")
187 |
188 | # concatenate hash_algorithm_uuid + namespace_uuid + name; then hash
189 | sha256 = hashlib.new("sha256")
190 | sha256.update(ALGORITHM_SHA256.bytes)
191 | sha256.update(NAMESPACE_DNS.bytes)
192 | sha256.update(bytes("www.example.com", "utf-8"))
193 | print(sha256.hexdigest())
194 | ```
195 |
196 | ---
197 |
198 | ### SHA256 (Testing a "v9") - 5c146b14-3c52-9afd-938a-375d0df1fbf6
199 | ```bash
200 | # Unset vars
201 | unset namespace
202 | unset name
203 | unset namespaceIDoctetString
204 | unset hash
205 | unset variantSpace
206 | unset variant
207 | unset newvVariant
208 |
209 | # Set Vars
210 | namespace=6ba7b810-9dad-11d1-80b4-00c04fd430c8
211 | name=www.example.com
212 |
213 | # Convert Namespace into string of octets
214 | # \x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8
215 | namespaceIDoctetString=$(echo -n $namespace | sed 's/-//g' | sed 's/.\{2\}/\\x&/g')
216 |
217 | # Compute hash
218 | # 5c146b143c524afd938a375d0df1fbf6fe12a66b645f72f6158759387e51f3c8
219 | hash=$(echo -n -e $namespaceIDoctetString$name | sha256sum)
220 |
221 | # Get the variant hex, convert to uppercase for BC in next step
222 | # 9
223 | variantSpace=$(echo $hash | sed -r 's/^.{16}(.{1}).{15}.*/\1/' | tr '[:lower:]' '[:upper:]')
224 |
225 | # Convert hex to bin ensure always 4 char length and replace upper two chars with 1 and 0
226 | # 1001
227 | variant=$(echo "obase=2; ibase=16; $variantSpace" | bc | awk '{ printf "%04d\n", $0 }' | sed -r 's/.*(..)$/10\1/')
228 |
229 | # convert back to hex
230 | # 9
231 | newVariant=$(echo "obase=16; ibase=2; $variant" | bc)
232 |
233 | # replace Ver (9) and Var, add Dashes, anything remaining is dropped, convert back to lowercase
234 | echo $hash | sed -r 's/^(.{12}).{1}(.{19})/\13\2/' | sed -re "s/(.{8})(.{4}).{1}(.{3}).{1}(.{3})(.{12}).*/\1-\2-9\3-$newVariant\4-\5/" | tr '[:upper:]' '[:lower:]'
235 | # 5c146b14-3c52-9afd-938a-375d0df1fbf6
236 | ```
237 |
238 | ---
239 |
240 | # Testing and Comparing Results
241 |
242 | ### Python3
243 | - https://github.com/python/cpython/blob/main/Lib/uuid.py
244 | ```python
245 | >>> import uuid
246 | >>> uuid.uuid3(uuid.NAMESPACE_DNS, "www.example.com")
247 | UUID('5df41881-3aed-3515-88a7-2f4a814cf09e')
248 | >>> uuid.uuid5(uuid.NAMESPACE_DNS, "www.example.com")
249 | UUID('2ed6657d-e927-568b-95e1-2665a8aea6a2')
250 | >>>
251 | ```
252 |
253 | ### UUID Tools (PHP)
254 | - https://github.com/aarreedd/uuidtools.com
255 | - https://www.uuidtools.com/api/generate/v3/namespace/6ba7b810-9dad-11d1-80b4-00c04fd430c8/name/base64:d3d3LmV4YW1wbGUuY29t
256 | - https://www.uuidtools.com/api/generate/v5/namespace/6ba7b810-9dad-11d1-80b4-00c04fd430c8/name/base64:d3d3LmV4YW1wbGUuY29t
257 |
258 | ### Javascript - https://github.com/uuidjs/uuid/blob/main/src/v35.js
259 | TODO
260 |
261 | ### uuidgen (libuud)
262 | - https://github.com/util-linux/util-linux/blob/master/misc-utils/uuidgen.c
263 | - https://github.com/util-linux/util-linux/blob/master/libuuid/src/gen_uuid.c
264 | ```c
265 | kydavis@ubuntu-server:~$ uuidgen -m -N www.example.com -n @dns
266 | 5df41881-3aed-3515-88a7-2f4a814cf09e
267 |
268 | kydavis@ubuntu-server:~$ uuidgen -s -N www.example.com -n @dns
269 | 2ed6657d-e927-568b-95e1-2665a8aea6a2
270 | ```
271 |
272 | ---
273 |
274 | # Other Notes
275 | - uuidgen with an MD5 hash where variant was hex xb computes the new var to x9, all others compute to xb as b1011 already has first two bits set to 10 and modifying them is null.
276 | - Seems uuidgen (actually libuuid) are doing little endian or misunderstood which bits to change because of errata https://www.rfc-editor.org/errata/eid4976
277 | - Inputs of DNS namespace and www.kyzer.me as the name confirm allow an MD5 hash with var as xb before modification
278 | ```
279 | kydavis@ubuntu-server:~$ uuidgen -m -N www.kyzer.me -n @dns
280 | df6b5e88-8e20-3136-9785-e44f079d0b78
281 |
282 | >>> import uuid
283 | >>> uuid.uuid3(uuid.NAMESPACE_DNS, "www.kyzer.me")
284 | UUID('df6b5e88-8e20-3136-b785-e44f079d0b78')
285 | ```
286 |
--------------------------------------------------------------------------------
/editor-files/draft-peabody-dispatch-new-uuid-format-04.md:
--------------------------------------------------------------------------------
1 | ---
2 | v: 3
3 | docname: draft-peabody-dispatch-new-uuid-format-04
4 | cat: std
5 | updates: '4122'
6 | consensus: 'true'
7 | submissiontype: IETF
8 | pi:
9 | strict: 'yes'
10 | toc: 'yes'
11 | tocdepth: '3'
12 | symrefs: 'yes'
13 | sortrefs: 'yes' # accidentally correcting accident :-)
14 | title: New UUID Formats
15 | abbrev: new-uuid-format
16 | area: ART
17 | wg: dispatch
18 | kw: uuid
19 | date: 2022
20 |
21 | author:
22 | - name: Brad G. Peabody
23 | email: brad@peabody.io
24 | - name: Kyzer R. Davis
25 | email: kydavis@cisco.com
26 | normative:
27 | RFC4122:
28 | RFC4086:
29 | informative:
30 | LexicalUUID:
31 | target: https://github.com/twitter-archive/cassie
32 | title: A Scala client for Cassandra
33 | author:
34 | - org: Twitter
35 | date: 2012-11
36 | seriesinfo:
37 | commit: f6da4e0
38 | Snowflake:
39 | target: https://github.com/twitter-archive/snowflake/releases/tag/snowflake-2010
40 | title: >
41 | Snowflake is a network service for generating unique ID numbers at high
42 | scale with some simple guarantees.
43 | author:
44 | - org: Twitter
45 | date: 2014-05
46 | seriesinfo:
47 | Commit: b3f6a3c
48 | Flake:
49 | target: https://github.com/boundary/flake
50 | title: 'Flake: A decentralized, k-ordered id generation service in Erlang'
51 | author:
52 | - org: Boundary
53 | date: 2017-02
54 | seriesinfo:
55 | Commit: 15c933a
56 | ShardingID:
57 | target: https://instagram-engineering.com/sharding-ids-at-instagram-1cf5a71e5a5c
58 | title: Sharding & IDs at Instagram
59 | author:
60 | - org: Instagram Engineering
61 | date: 2012-12
62 | KSUID:
63 | target: https://github.com/segmentio/ksuid
64 | title: K-Sortable Globally Unique IDs
65 | author:
66 | - org: Segment
67 | date: 2020-07
68 | seriesinfo:
69 | Commit: bf376a7
70 | Elasticflake:
71 | target: https://github.com/ppearcy/elasticflake
72 | title: Sequential UUID / Flake ID generator pulled out of elasticsearch common
73 | author:
74 | - name: Paul Pearcy
75 | date: 2015-01
76 | seriesinfo:
77 | Commit: dd71c21
78 | FlakeID:
79 | target: https://github.com/T-PWK/flake-idgen
80 | title: Flake ID Generator
81 | author:
82 | - name: Tom Pawlak
83 | date: 2020-04
84 | seriesinfo:
85 | Commit: fcd6a2f
86 | Sonyflake:
87 | target: https://github.com/sony/sonyflake
88 | title: A distributed unique ID generator inspired by Twitter's Snowflake
89 | author:
90 | - org: Sony
91 | date: 2020-08
92 | seriesinfo:
93 | Commit: 848d664
94 | orderedUuid:
95 | target: https://itnext.io/laravel-the-mysterious-ordered-uuid-29e7500b4f8
96 | title: 'Laravel: The mysterious "Ordered UUID"'
97 | author:
98 | - name: Italo Baeza Cabrera
99 | date: 2020-01
100 | COMBGUID:
101 | target: https://github.com/richardtallent/RT.Comb
102 | title: Creating sequential GUIDs in C# for MSSQL or PostgreSql
103 | author:
104 | - name: Richard Tallent
105 | date: 2020-12
106 | seriesinfo:
107 | Commit: '2759820'
108 | ULID:
109 | target: https://github.com/ulid/spec
110 | title: Universally Unique Lexicographically Sortable Identifier
111 | author:
112 | - name: Alizain Feerasta
113 | date: 2019-05
114 | seriesinfo:
115 | Commit: d0c7170
116 | SID:
117 | target: https://github.com/chilts/sid
118 | title: 'sid : generate sortable identifiers'
119 | author:
120 | - name: Andrew Chilton
121 | date: 2019-06
122 | seriesinfo:
123 | Commit: 660e947
124 | pushID:
125 | target: https://firebase.googleblog.com/2015/02/the-2120-ways-to-ensure-unique_68.html
126 | title: The 2^120 Ways to Ensure Unique Identifiers
127 | author:
128 | - org: Google
129 | date: 2015-02
130 | XID:
131 | target: https://github.com/rs/xid
132 | title: Globally Unique ID Generator
133 | author:
134 | - name: Olivier Poitrey
135 | date: 2020-10
136 | seriesinfo:
137 | Commit: efa678f
138 | ObjectID:
139 | target: https://docs.mongodb.com/manual/reference/method/ObjectId/
140 | title: ObjectId - MongoDB Manual
141 | author:
142 | - org: MongoDB
143 | date: false # XXX check
144 | CUID:
145 | target: https://github.com/ericelliott/cuid
146 | title: Collision-resistant ids optimized for horizontal scaling and performance.
147 | author:
148 | - name: Eric Elliott
149 | date: 2020-10
150 | seriesinfo:
151 | Commit: 215b27b
152 | IEEE754:
153 | target: https://standards.ieee.org/ieee/754/6210/
154 | title: IEEE Standard for Floating-Point Arithmetic.
155 | author:
156 | - org: IEEE
157 | date: 2019-07
158 | seriesinfo:
159 | Series: 754-2019
160 |
161 | --- abstract
162 |
163 | This document presents new Universally Unique Identifier (UUID) formats for
164 | use in modern applications and databases.
165 |
166 | --- middle
167 |
168 | # Introduction {#Background}
169 |
170 | Many things have changed in the time since UUIDs were originally created.
171 | Modern applications have a need to create and utilize UUIDs as the primary
172 | identifier for a variety of different items in complex computational systems,
173 | including but not limited to database keys, file names, machine or system
174 | names, and identifiers for event-driven transactions.
175 |
176 | One area UUIDs have gained popularity is as database keys.
177 | This stems from the increasingly distributed nature of modern applications.
178 | In such cases, "auto increment" schemes often used by databases do not work
179 | well, as the effort required to coordinate unique numeric identifiers across
180 | a network can easily become a burden.
181 | The fact that UUIDs can be used to create unique, reasonably short values
182 | in distributed systems without requiring synchronization makes them a good
183 | alternative, but UUID versions 1-5 lack certain other desirable characteristics:
184 |
185 |
186 | 1. Non-time-ordered UUID versions such as UUIDv4 have poor database index
187 | locality.
188 | Meaning new values created in succession are not close to each other in
189 | the index and thus require inserts to be performed at random
190 | locations.
191 | The negative performance effects of which on common structures used for
192 | this (B-tree and its variants) can be dramatic.
193 |
194 | 1. The 100-nanosecond, Gregorian epoch used in UUIDv1 timestamps is uncommon
195 | and difficult to represent accurately using a standard number format such
196 | as {{IEEE754}}.
197 |
198 |
199 |
200 | 1. Introspection/parsing is required to order by time sequence; as opposed to
201 | being able to perform a simple byte-by-byte comparison.
202 |
203 |
204 |
205 | 1. Privacy and network security issues arise from using a MAC address in the
206 | node field of Version 1 UUIDs.
207 | Exposed MAC addresses can be used as an attack surface to locate machines
208 | and reveal various other
209 | information about such machines (minimally manufacturer, potentially other
210 | details). Additionally, with the advent of virtual machines and containers,
211 | MAC address uniqueness is no longer guaranteed.
212 |
213 |
214 |
215 | 1. Many of the implementation details specified in {{RFC4122}} involve trade
216 | offs that are neither possible to specify for all applications nor
217 | necessary to produce interoperable implementations.
218 |
219 |
220 |
221 | 1. {{RFC4122}} does not distinguish between the requirements for generation
222 | of a UUID versus an application which simply stores one, which are often
223 | different.
224 |
225 |
226 |
227 | Due to the aforementioned issue, many widely distributed database applications
228 | and large application vendors have sought to solve the problem of creating
229 | a better
230 | time-based, sortable unique identifier for use as a database key. This has
231 | lead to numerous implementations
232 | over the past 10+ years solving the same problem in slightly different ways.
233 |
234 | While preparing this specification the following 16 different implementations
235 | were analyzed for trends in total ID length, bit Layout, lexical formatting/encoding,
236 | timestamp type, timestamp format, timestamp accuracy, node format/components,
237 | collision handling and multi-timestamp tick generation sequencing.
238 |
239 |
240 | {: spacing="compact"}
241 | 1. {{ULID}} by A. Feerasta
242 | 1. {{LexicalUUID}} by Twitter
243 | 1. {{Snowflake}} by Twitter
244 | 1. {{Flake}} by Boundary
245 | 1. {{ShardingID}} by Instagram
246 | 1. {{KSUID}} by Segment
247 | 1. {{Elasticflake}} by P. Pearcy
248 | 1. {{FlakeID}} by T. Pawlak
249 | 1. {{Sonyflake}} by Sony
250 | 1. {{orderedUuid}} by IT. Cabrera
251 | 1. {{COMBGUID}} by R. Tallent
252 | 1. {{SID}} by A. Chilton
253 | 1. {{pushID}} by Google
254 | 1. {{XID}} by O. Poitrey
255 | 1. {{ObjectID}} by MongoDB
256 | 1. {{CUID}} by E. Elliott
257 |
258 | An inspection of these implementations and the issues described above has
259 | led to this document which attempts to adapt UUIDs to address these issues.
260 |
261 |
262 | # Terminology
263 |
264 | ## Requirements Language {#requirements_language}
265 |
266 | {::boilerplate bcp14-tagged}
267 |
268 | ## Abbreviations {#acronyms}
269 |
270 | The following abbreviations are used in this document:
271 |
272 | {: indent="14"}
273 | UUID
274 | : Universally Unique Identifier {{RFC4122}}
275 |
276 | CSPRNG
277 | : Cryptographically Secure Pseudo-Random Number Generator
278 |
279 | MAC
280 | : Media Access Control
281 |
282 | MSB
283 | : Most Significant Bit
284 |
285 | DBMS
286 | : Database Management System
287 |
288 |
289 |
290 | # Summary of Changes {#Changes}
291 |
292 | The following UUIDs are hereby introduced:
293 |
294 | {: vspace='0'}
295 | UUID version 6 (UUIDv6)
296 | : A re-ordering of UUID version 1 so it is sortable as an opaque sequence of
297 | bytes. Easy to implement given an existing UUIDv1 implementation. See {{uuidv6}}.
298 |
299 | UUID version 7 (UUIDv7)
300 | : An entirely new time-based UUID bit layout sourced from the widely implemented
301 | and well known Unix Epoch timestamp source. See {{v7}}.
302 |
303 | UUID version 8 (UUIDv8)
304 | : A free-form UUID format which has no explicit requirements except maintaining
305 | backward compatibility. See {{v8}}.
306 |
307 | Max UUID
308 | : A specialized UUID which is the inverse of {{RFC4122, Section 4.1.7}}.
309 | See {{maxuuid}}.
310 |
311 | ## changelog {#changelog}
312 | {:removeinrfc}
313 |
314 | draft-04
315 |
316 |
317 | {: spacing="compact"}
318 | - Fixed bad title in IEEE754 Normative Reference
319 | - Fixed bad GMT offset in Test Vector Appendix
320 | - Removed MAY in Counters section
321 | - Condensed Counter Type into Counter Methods to reduce text
322 | - Removed option for random increment along with fixed-length counter
323 | - Described how to handle scenario where New UUID less than Old UUID
324 | - Allow timestamp increment if counter overflows
325 | - Replaced UUIDv8 C code snippet with full generation example
326 | - Fixed RFC4086 Reference link
327 | - Describe reseeding best practice for CSPRNG
328 | - Changed MUST to SHOULD removing requirement for absolute monotonicity
329 |
330 | draft-03
331 |
332 | {: spacing="compact"}
333 | - Reworked the draft body to make the content more concise
334 | - UUIDv6 section reworked to just the reorder of the timestamp
335 | - UUIDv7 changed to simplify timestamp mechanism to just millisecond Unix
336 | timestamp
337 | - UUIDv8 relaxed to be custom in all elements except version and variant
338 | - Introduced Max UUID.
339 | - Added C code samples in Appendix.
340 | - Added test vectors in Appendix.
341 | - Version and Variant section combined into one section.
342 | - Changed from pseudo-random number generators to cryptographically secure
343 | pseudo-random number generator (CSPRNG).
344 | - Combined redundant topics from all UUIDs into sections such as Timestamp
345 | granularity, Monotonicity and Counters, Collision Resistance, Sorting, and
346 | Unguessability, etc.
347 | - Split Encoding and Storage into Opacity and DBMS and Database Considerations
348 | - Reworked Global Uniqueness under new section Global and Local Uniqueness
349 | - Node verbiage only used in UUIDv6 all others reference random/rand instead
350 | - Clock sequence verbiage changed simply to counter in any section other
351 | than UUIDv6
352 | - Added Abbreviations section
353 | - Updated IETF Draft XML Layout
354 | - Added information about little-endian UUIDs
355 |
356 | draft-02
357 |
358 | {: spacing="compact"}
359 | - Added Changelog
360 | - Fixed misc. grammatical errors
361 | - Fixed section numbering issue
362 | - Fixed some UUIDvX reference issues
363 | - Changed all instances of "motonic" to "monotonic"
364 | - Changed all instances of "#-bit" to "# bit"
365 | - Changed "proceeding" verbiage to "after" in section 7
366 | - Added details on how to pad 32 bit Unix timestamp to 36 bits in UUIDv7
367 | - Added details on how to truncate 64 bit Unix timestamp to 36 bits in UUIDv7
368 | - Added forward reference and bullet to UUIDv8 if truncating 64 bit Unix
369 | Epoch is not an option.
370 | - Fixed bad reference to non-existent "time_or_node" in section 4.5.4
371 |
372 | draft-01
373 |
374 | {: spacing="compact"}
375 | - Complete rewrite of entire document.
376 | - The format, flow and verbiage used in the specification has been reworked
377 | to mirror the original RFC 4122 and current IETF standards.
378 | - Removed the topics of UUID length modification, alternate UUID text formats,
379 | and alternate UUID encoding techniques.
380 | - Research into 16 different historical and current implementations of time-based
381 | universal identifiers was completed at the end of 2020 in attempt to identify
382 | trends which have directly influenced design decisions in this draft document
383 | (https://github.com/uuid6/uuid6-ietf-draft/tree/master/research)
384 | - Prototype implementation have been completed for UUIDv6, UUIDv7, and UUIDv8
385 | in various languages by many GitHub community members. (https://github.com/uuid6/prototypes)
386 |
387 | # Variant and Version Fields {#variant_and_version_fields}
388 |
389 | The variant bits utilized by UUIDs in this specification
390 | remain in the same octet as originally defined by {{RFC4122}}{: section="4.1.1" sectionFormat="comma"}.
391 |
392 | The next table details Variant 10xx (8/9/A/B) and the new versions defined
393 | by this specification.
394 | A complete guide to all versions within this variant has been includes in {{old_var_table}}.
395 |
396 | | Msb0 | Msb1 | Msb2 | Msb3 | Version | Description |
397 | | 0 | 1 | 1 | 0 | 6 | Reordered Gregorian time-based UUID specified in this document. |
398 | | 0 | 1 | 1 | 1 | 7 | Unix Epoch time-based UUID specified in this document. |
399 | | 1 | 0 | 0 | 0 | 8 | Reserved for custom UUID formats specified in this document |
400 | {: title='New UUID variant 10xx (8/9/A/B) versions defined by this specification'}
401 |
402 | For UUID version 6, 7 and 8 the variant field placement from {{RFC4122}} are unchanged.
403 | An example version/variant layout for UUIDv6 follows the table where M is
404 | the version and N is the variant.
405 |
406 |
407 | ~~~~
408 | 00000000-0000-6000-8000-000000000000
409 | 00000000-0000-6000-9000-000000000000
410 | 00000000-0000-6000-A000-000000000000
411 | 00000000-0000-6000-B000-000000000000
412 | xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
413 | ~~~~
414 | {: title='UUIDv6 Variant Examples'}
415 |
416 |
417 | # New Formats {#format}
418 |
419 | The UUID format is 16 octets; the variant bits in conjunction with the version
420 | bits described in the next section in determine finer structure.
421 |
422 | ## UUID Version 6 {#uuidv6}
423 |
424 | UUID version 6 is a field-compatible version of UUIDv1, reordered for improved
425 | DB locality.
426 | It is expected that UUIDv6 will primarily be used in contexts where there
427 | are existing v1 UUIDs.
428 | Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 instead.
429 |
430 | Instead of splitting the timestamp into the low, mid and high sections from
431 | UUIDv1, UUIDv6 changes this sequence so timestamp bytes are stored from most
432 | to least significant.
433 | That is, given a 60 bit timestamp value as specified for UUIDv1 in {{RFC4122}}{: section="4.1.4" sectionFormat="comma"},
434 | for UUIDv6, the first 48 most significant bits are stored
435 | first, followed by the 4 bit version (same position), followed by the remaining
436 | 12 bits of the original 60 bit timestamp.
437 |
438 | The clock sequence bits remain unchanged from their usage and position in {{RFC4122}}{: section="4.1.5" sectionFormat="comma"}.
439 |
440 | The 48 bit node SHOULD be set to a pseudo-random value however implementations
441 | MAY choose to retain the old MAC address behavior from {{RFC4122}}{: section="4.1.6" sectionFormat="comma"} and {{RFC4122}}{: section="4.5" sectionFormat="comma"}. For more information on MAC address usage within UUIDs see the {{Security}}
442 |
443 | The format for the 16-byte, 128 bit UUIDv6 is shown in Figure 1
444 |
445 |
446 | ~~~~
447 | 0 1 2 3
448 | 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
449 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
450 | | time_high |
451 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
452 | | time_mid | time_low_and_version |
453 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
454 | |clk_seq_hi_res | clk_seq_low | node (0-1) |
455 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
456 | | node (2-5) |
457 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
458 | ~~~~
459 | {: title='UUIDv6 Field and Bit Layout'}
460 |
461 | {: vspace='0'}
462 |
463 | time_high:
464 | : The most significant 32 bits of the 60 bit starting timestamp.
465 | Occupies bits 0 through 31 (octets 0-3)
466 |
467 | time_mid:
468 | : The middle 16 bits of the 60 bit starting timestamp.
469 | Occupies bits 32 through 47 (octets 4-5)
470 |
471 | time_low_and_version:
472 | : The first four most significant bits MUST contain
473 | the UUIDv6 version (0110) while the remaining 12 bits will contain
474 | the least significant 12 bits from the 60 bit starting timestamp.
475 | Occupies bits 48 through 63 (octets 6-7)
476 |
477 | clk_seq_hi_res:
478 | : The first two bits MUST be set to the UUID variant (10)
479 | The remaining 6 bits contain the high portion of the clock sequence.
480 | Occupies bits 64 through 71 (octet 8)
481 |
482 | clock_seq_low:
483 | : The 8 bit low portion of the clock sequence.
484 | Occupies bits 72 through 79 (octet 9)
485 |
486 | node:
487 | : 48 bit spatially unique identifier
488 | Occupies bits 80 through 127 (octets 10-15)
489 |
490 | With UUIDv6 the steps for splitting the timestamp into time_high and time_mid
491 | are OPTIONAL
492 | since the 48 bits of time_high and time_mid will remain in the same order.
493 | An extra step of splitting the first 48 bits of the timestamp into the most
494 | significant
495 | 32 bits and least significant 16 bits proves useful when reusing an existing
496 | UUIDv1 implementation.
497 |
498 |
499 | ## UUID Version 7 {#v7}
500 |
501 | UUID version 7 features a time-ordered value field derived from the widely
502 | implemented and well known Unix Epoch timestamp source, the number of milliseconds
503 | since midnight 1 Jan 1970 UTC, leap seconds excluded.
504 | As well as improved entropy characteristics over versions 1 or 6.
505 |
506 | Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 if
507 | possible.
508 |
509 |
510 | ~~~~
511 | 0 1 2 3
512 | 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
513 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
514 | | unix_ts_ms |
515 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
516 | | unix_ts_ms | ver | rand_a |
517 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
518 | |var| rand_b |
519 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
520 | | rand_b |
521 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
522 | ~~~~
523 | {: title='UUIDv7 Field and Bit Layout'}
524 |
525 | {: vspace='0'}
526 |
527 | unix_ts_ms:
528 | : 48 bit big-endian unsigned number of Unix epoch timestamp as per {{timestamp_granularity}}.
529 |
530 | ver:
531 | : 4 bit UUIDv7 version set as per {{variant_and_version_fields}}
532 |
533 | rand_a:
534 | : 12 bits pseudo-random data to provide uniqueness as per {{monotonicity_counters}} and {{unguessability}}.
535 |
536 | var:
537 | : The 2 bit variant defined by {{variant_and_version_fields}}.
538 |
539 | rand_b:
540 | : The final 62 bits of pseudo-random data to provide uniqueness as per {{monotonicity_counters}} and {{unguessability}}.
541 |
542 |
543 | ## UUID Version 8 {#v8}
544 |
545 | UUID version 8 provides an RFC-compatible format for experimental or vendor-specific
546 | use cases.
547 | The only requirement is that the variant and version bits MUST be set as
548 | defined in {{variant_and_version_fields}}.
549 | UUIDv8's uniqueness will be implementation-specific and SHOULD NOT be assumed.
550 |
551 | The only explicitly defined bits are the Version and Variant leaving 122
552 | bits
553 | for implementation specific time-based UUIDs. To be clear:
554 | UUIDv8 is not a replacement for UUIDv4 where all 122 extra bits are
555 | filled with random data.
556 |
557 | Some example situations in which UUIDv8 usage could occur:
558 |
559 |
560 | * An implementation would like to embed extra information
561 | within the UUID other than what is defined in this document.
562 |
563 |
564 |
565 | * An implementation has other application/language restrictions which
566 | inhibit the use of one of the current UUIDs.
567 |
568 |
569 |
570 |
571 | ~~~~
572 | 0 1 2 3
573 | 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
574 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
575 | | custom_a |
576 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
577 | | custom_a | ver | custom_b |
578 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
579 | |var| custom_c |
580 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
581 | | custom_c |
582 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
583 | ~~~~
584 | {: title='UUIDv8 Field and Bit Layout'}
585 |
586 | {: vspace='0'}
587 |
588 | custom_a:
589 | : The first 48 bits of the layout that can be filled as an implementation sees
590 | fit.
591 |
592 | ver:
593 | : The 4 bit version field as defined by {{variant_and_version_fields}}
594 |
595 | custom_b:
596 | : 12 more bits of the layout that can be filled as an implementation sees fit.
597 |
598 | var:
599 | : The 2 bit variant field as defined by {{variant_and_version_fields}}.
600 |
601 | custom_c:
602 | : The final 62 bits of the layout immediatly following the var field to be
603 | filled as an implementation sees fit.
604 |
605 |
606 | ## Max UUID {#maxuuid}
607 |
608 | The Max UUID is special form of UUID that is specified to have all 128 bits
609 | set to 1. This UUID can be thought of as the inverse of Nil UUID defined
610 | in {{RFC4122}}{: section="4.1.7" sectionFormat="comma"}
611 |
612 |
613 | ~~~~
614 | FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF
615 | ~~~~
616 | {: title='Max UUID Format'}
617 |
618 |
619 |
620 | # UUID Best Practices {#uuid_best_practices}
621 |
622 | The minimum requirements for generating UUIDs are
623 | described in this document for each version.
624 | Everything else is an implementation detail and
625 | up to the implementer to decide what is appropriate for a given
626 | implementation. That being said, various relevant factors are covered
627 | below to help guide an implementer through the different trade-offs among
628 | differing UUID implementations.
629 |
630 | ## Timestamp Granularity {#timestamp_granularity}
631 |
632 | UUID timestamp source, precision and length was the topic of great debate
633 | while creating this specification. As such choosing the right timestamp for
634 | your application is a very important topic. This section will detail some
635 | of the most common points on this topic.
636 |
637 | {: vspace='0'}
638 |
639 | Reliability:
640 | : Implementations SHOULD use the current timestamp from a reliable source to
641 | provide values that are time-ordered and continually increasing.
642 | Care SHOULD be taken to ensure that timestamp changes from the environment
643 | or operating system are handled in a way that is consistent with implementation
644 | requirements.
645 | For example, if it is possible for the system clock to move backward due
646 | to either manual adjustment or corrections from a time synchronization protocol,
647 | implementations must decide how to handle such cases. (See Altering, Fuzzing,
648 | or Smearing bullet below.)
649 |
650 | Source:
651 | : UUID version 1 and 6 both utilize a Gregorian epoch timestamp while UUIDv7
652 | utilizes a Unix Epoch timestamp. If other timestamp sources or a custom timestamp
653 | epoch are required UUIDv8 SHOULD be leveraged.
654 |
655 | Sub-second Precision and Accuracy:
656 | : Many levels of precision exist for timestamps: milliseconds, microseconds,
657 | nanoseconds, and beyond.
658 | Additionally fractional representations of sub-second precision may be desired
659 | to mix various levels of precision in a time-ordered manner.
660 | Furthermore, system clocks themselves have an underlying granularity and
661 | it is frequently less than the precision offered by the operating system.
662 | With UUID version 1 and 6, 100-nanoseconds of precision are present while
663 | UUIDv7 features fixed millisecond level of precision within the Unix epoch
664 | that does not exceed the granularity capable in most modern systems.
665 | For other levels of precision UUIDv8 SHOULD be utilized.
666 |
667 | Length:
668 | : The length of a given timestamp directly impacts how long a given UUID will
669 | be valid.
670 | That is, how many timestamp ticks can be contained in a UUID before the maximum
671 | value for the timestamp field is reached.
672 | Care should be given to ensure that the proper length is selected for a given
673 | timestamp.
674 | UUID version 1 and 6 utilize a 60 bit timestamp and UUIDv7 features a 48
675 | bit timestamp.
676 |
677 | Altering, Fuzzing, or Smearing:
678 | : Implementations MAY alter the actual timestamp. Some examples included security
679 | considerations around providing a real clock value within a UUID, to correct
680 | inaccurate clocks or to handle leap seconds. This specification makes no
681 | requirement or guarantee about how close the clock value needs to be to actual
682 | time.
683 |
684 | Padding:
685 | : When timestamp padding is required, implementations MUST pad the most significant
686 | bits (left-most) bits with zeros. An example is padding the most significant,
687 | left-most bits of a 32 bit Unix timestamp with zero's to fill out the 48
688 | bit timestamp in UUIDv7.
689 |
690 | Truncating:
691 | : Similarly, when timestamps need to be truncated: the lower, least significant
692 | bits MUST be used. An example would be truncating a 64 bit Unix timestamp
693 | to the least significant, right-most 48 bits for UUIDv7.
694 |
695 |
696 | ## Monotonicity and Counters {#monotonicity_counters}
697 |
698 | Monotonicity is the backbone of time-based sortable UUIDs. Naturally time-based
699 | UUIDs from this document will be monotonic due to an embedded timestamp however
700 | implementations can guarantee additional monotonicity via the concepts covered
701 | in this section.
702 |
703 | Additionally, care SHOULD be taken to ensure UUIDs generated in batches are
704 | also monotonic. That is, if one-thousand UUIDs are generated for the same
705 | timestamp; there is sufficient logic for organizing the creation order of
706 | those one-thousand UUIDs.
707 | For batch UUID creation implementions MAY utilize a monotonic counter which
708 | SHOULD increment for each UUID created during a given timestamp.
709 |
710 | For single-node UUID implementations that do not need to create batches of
711 | UUIDs, the embedded timestamp within UUID version 1, 6, and 7 can provide
712 | sufficient monotonicity guarantees by simply ensuring that timestamp increments
713 | before creating a new UUID. For the topic of Distributed Nodes please refer
714 | to {{distributed_shared_knowledge}}
715 |
716 | Implementations SHOULD choose one method for single-node UUID implementations
717 | that require batch UUID creation.
718 |
719 | {: vspace='0'}
720 |
721 | Fixed-Length Dedicated Counter Bits (Method 1):
722 | : This references the practice of allocating a specific number of bits in the
723 | UUID layout to the sole purpose of tallying the total number of UUIDs created
724 | during a given UUID timestamp tick.
725 | Positioning of a fixed bit-length counter SHOULD be immediatly after the
726 | embedded timestamp. This promotes sortability and allows random data generation
727 | for each counter increment.
728 | With this method rand_a section of UUIDv7 SHOULD be utilized as fixed-length
729 | dedicated counter bits that are incremented by one for every UUID generation.
730 | The trailing random bits generated for each new UUID in rand_b can help produce
731 | unguessable UUIDs. In the event more counter bits are required the most significant,
732 | left-most, bits of rand_b MAY be leveraged as additional counter bits.
733 |
734 | Monotonic Random (Method 2):
735 | : With this method the random data is extended to also double as a counter.
736 | This monotonic random can be thought of as a "randomly seeded counter" which
737 | MUST be incremented in the least significant position for each UUID created
738 | on a given timestamp tick.
739 | UUIDv7's rand_b section SHOULD be utilized with this method to handle batch
740 | UUID generation during a single timestamp tick.
741 | The increment value for every UUID generation SHOULD be a random integer
742 | of any desired length larger than zero. It ensures the UUIDs retain the required
743 | level of unguessability characters provided by the underlying entropy.
744 | The increment value MAY be one when the amount of UUIDs generated in a particular
745 | period of time is important and guessability is not an issue. However, it
746 | SHOULD NOT be used by implementations that favor unguessiblity, as the resulting
747 | values are easily guessable.
748 |
749 | The following sub-topics cover topics related solely with creating reliable
750 | fixed-length dedicated counters:
751 |
752 | {: vspace='0'}
753 |
754 | Fixed-Length Dedicated Counter Seeding:
755 | : Implementations utilizing fixed-length counter method SHOULD randomly initialize
756 | the counter with each new timestamp tick.
757 | However, when the timestamp has not incremented; the counter SHOULD be frozen
758 | and incremented via the desired increment logic.
759 | When utilizing a randomly seeded counter alongside Method 1; the random MAY
760 | be regenerated with each counter increment without impacting sortability.
761 | The downside is that Method 1 is prone to overflows if a counter of adequate
762 | length is not selected or the random data generated leaves little room for
763 | the required number of increments.
764 | Implementations utilizing fixed-length counter method MAY also choose to
765 | randomly initialize a portion counter rather than the entire counter. For
766 | example, a 24 bit counter could have the 23 bits in least-significant, right-most,
767 | position randomly initialized. The remaining most significant, left-most
768 | counter bits are initialized as zero for the sole purpose of guarding against
769 | counter rollovers.
770 |
771 | Fixed-Length Dedicated Counter Length:
772 | : Care MUST be taken to select a counter bit-length that can properly handle
773 | the level of timestamp precision in use.
774 | For example, millisecond precision SHOULD require a larger counter than a
775 | timestamp with nanosecond precision.
776 | General guidance is that the counter SHOULD be at least 12 bits but no longer
777 | than 42 bits.
778 | Care SHOULD also be given to ensure that the counter length selected leaves
779 | room for sufficient entropy in the random portion of the UUID after the counter.
780 | This entropy helps improve the unguessability characteristics of UUIDs created
781 | within the batch.
782 |
783 | The following sub-topics cover rollover handling with either type of counter
784 | method:
785 |
786 | {: vspace='0'}
787 |
788 | Counter Rollover Guards:
789 | : The technique from Fixed-Length Dedicated Counter Seeding which describes
790 | allocating a segment of the fixed-length counter as a rollover guard is also
791 | helpful to mitigate counter rollover issues.
792 | This same technique can be leveraged with Monotonic random counter methods
793 | by ensuring the total length of a possible increment in the least significant,
794 | right most position is less than the total length of the random being incremented.
795 | As such the most significant, left-most, bits can be incremented as rollover
796 | guarding.
797 |
798 | Counter Rollover Handling:
799 | : Counter rollovers SHOULD be handled by the application to avoid sorting issues.
800 | The general guidance is that applications that care about absolute monotonicity
801 | and sortability SHOULD freeze the counter and wait for the timestamp to advance
802 | which ensures monotonicity is not broken.
803 | Alternatively, implementations MAY increment the timestamp ahead of the actual
804 | time and reinitialize the counter.
805 |
806 | Implementations MAY use the following logic to ensure UUIDs featuring embedded
807 | counters are monotonic in nature:
808 |
809 |
810 | 1. Compare the current timestamp against the previously stored timestamp.
811 |
812 |
813 |
814 | 1. If the current timestamp is equal to the previous timestamp; increment the
815 | counter according to the desired method.
816 |
817 |
818 |
819 | 1. If the current timestamp is greater than the previous timestamp; re-initialize
820 | the desired counter method to the new timestamp and generate new random bytes
821 | (if the bytes were frozen or being used as the seed for a monotonic counter).
822 |
823 |
824 |
825 | Implementations SHOULD check if the the currently generated UUID is greater
826 | than the previously generated UUID. If this is not the case then any number
827 | of things could have occurred. Such as, but not limited to, clock rollbacks,
828 | leap second handling or counter rollovers. Applications SHOULD embed sufficient
829 | logic to catch these scenarios and correct the problem ensuring the next
830 | UUID generated is greater than the previous. To handle this scenario, the
831 | general guidance is that application MAY reuse the previous timestamp and
832 | increment the previous counter method.
833 |
834 |
835 | ## Distributed UUID Generation {#distributed_shared_knowledge}
836 |
837 | Some implementations MAY desire to utilize multi-node, clustered, applications
838 | which involve two or more
839 | nodes independently generating UUIDs that will be stored in a common location.
840 | While UUIDs already feature sufficient entropy to ensure that the chances
841 | of collision are low as the total number of nodes increase; so does the likelihood
842 | of a collision.
843 | This section will detail the approaches that MAY be utilized by multi-node
844 | UUID implementations in distributed environments.
845 |
846 | {: vspace='0'}
847 |
848 | Centralized Registry:
849 | : With this method all nodes tasked with creating UUIDs consult a central registry
850 | and confirm the generated value is unique. As applications scale the communication
851 | with the central registry could become a bottleneck and impact UUID generation
852 | in a negative way. Utilization of shared knowledge schemes with central/global
853 | registries is outside the scope of this specification.
854 |
855 | Node IDs:
856 | : With this method, a pseudo-random Node ID value is placed within the UUID
857 | layout.
858 | This identifier helps ensure the bit-space for a given node is unique, resulting
859 | in UUIDs that do not conflict with any other UUID created by another node
860 | with a different node id.
861 | Implementations that choose to leverage an embedded node id SHOULD utilize
862 | UUIDv8.
863 | The node id SHOULD NOT be an IEEE 802 MAC address as per {{Security}}.
864 | The location and bit length are left to implementations and are outside the
865 | scope of this specification.
866 | Furthermore, the creation and negotiation of unique node ids among nodes
867 | is also out of scope for this specification.
868 |
869 | Utilization of either a Centralized Registry or Node ID are not required
870 | for implementing UUIDs in this specification. However implementations SHOULD
871 | utilize one of the two aforementioned methods if distributed UUID generation
872 | is a requirement.
873 |
874 |
875 | ## Collision Resistance {#collision_resistance}
876 |
877 | Implementations SHOULD weigh the consequences of UUID collisions within their
878 | application and when deciding between UUID versions that use entropy (random)
879 | versus the other components such as {{timestamp_granularity}} and {{monotonicity_counters}}.
880 | This is especially true for distributed node collision resistance as defined
881 | by {{distributed_shared_knowledge}}.
882 |
883 | There are two example scenarios below which help illustrate the varying seriousness
884 | of a collision within an application.
885 |
886 | {: vspace='0'}
887 |
888 | Low Impact
889 | : A UUID collision generated a duplicate log entry which results in incorrect
890 | statistics derived from the data. Implementations that are not negatively
891 | affected by collisions may continue with the entropy and uniqueness provided
892 | by the traditional UUID format.
893 |
894 | High Impact:
895 | : A duplicate key causes an airplane to receive the wrong course which puts
896 | people's lives at risk. In this scenario there is no margin for error. Collisions
897 | MUST be avoided and failure is unacceptable. Applications dealing with this
898 | type of scenario MUST employ as much collision resistance as possible within
899 | the given application context.
900 |
901 |
902 | ## Global and Local Uniqueness {#global_local_uniqueness}
903 |
904 | UUIDs created by this specification MAY be used to provide local uniqueness
905 | guarantees.
906 | For example, ensuring UUIDs created within a local application context are
907 | unique within a database MAY be sufficient for some implementations where
908 | global uniqueness outside of the application context, in other applications,
909 | or around the world is not required.
910 |
911 | Although true global uniqueness is impossible to guarantee without a shared
912 | knowledge scheme; a shared knowledge scheme is not required by UUID to provide
913 | uniqueness guarantees.
914 | Implementations MAY implement a shared knowledge scheme introduced in {{distributed_shared_knowledge}} as they see fit to extend the uniqueness guaranteed this specification and {{RFC4122}}.
915 |
916 |
917 | ## Unguessability {#unguessability}
918 |
919 | Implementations SHOULD utilize a cryptographically secure pseudo-random number
920 | generator (CSPRNG) to provide values that are both difficult to predict ("unguessable")
921 | and have a low likelihood of collision ("unique").
922 | Care SHOULD be taken to ensure the CSPRNG state is properly reseeded upon
923 | state changes, such as process forks, to ensure proper CSPRNG operation.
924 | CSPRNG ensures the best of {{collision_resistance}} and {{Security}} are present in modern UUIDs.
925 |
926 | Advice on generating cryptographic-quality random numbers can be found in {{RFC4086}}
927 |
928 |
929 | ## Sorting {#sorting}
930 |
931 | UUIDv6 and UUIDv7 are designed so that implementations that require sorting
932 | (e.g. database indexes) SHOULD sort as opaque raw bytes, without need for
933 | parsing or introspection.
934 |
935 | Time ordered monotonic UUIDs benefit from greater database index locality
936 | because the new values are near each other in the index.
937 | As a result objects are more easily clustered together for better performance.
938 | The real-world differences in this approach of index locality vs random data
939 | inserts can be quite large.
940 |
941 | UUIDs formats created by this specification SHOULD be Lexicographically sortable
942 | while in the textual representation.
943 |
944 | UUIDs created by this specification are crafted with big-ending byte order
945 | (network byte order) in mind. If Little-endian style is required a custom
946 | UUID format SHOULD be created using UUIDv8.
947 |
948 |
949 | ## Opacity {#opacity}
950 |
951 | UUIDs SHOULD be treated as opaque values and implementations SHOULD NOT examine
952 | the bits in a UUID to whatever extent is possible. However, where necessary,
953 | inspectors should refer to {{variant_and_version_fields}} for more information on determining UUID version and variant.
954 |
955 |
956 | ## DBMS and Database Considerations {#database_considerations}
957 |
958 | For many applications, such as databases, storing UUIDs as text is unnecessarily
959 | verbose, requiring 288 bits to represent 128 bit UUID values.
960 | Thus, where feasible, UUIDs SHOULD be stored within database applications
961 | as the underlying 128 bit binary value.
962 |
963 | For other systems, UUIDs MAY be stored in binary form or as text, as appropriate.
964 | The trade-offs to both approaches are as such:
965 |
966 |
967 | * Storing as binary requires less space and may result in faster data access.
968 |
969 |
970 |
971 | * Storing as text requires more space but may require less translation if the
972 | resulting text form is to be used after retrieval and thus maybe simpler
973 | to implement.
974 |
975 |
976 |
977 | DBMS vendors are encouraged to provide functionality to generate and store
978 | UUID formats defined by this specification for use as identifiers or left
979 | parts of identifiers such as, but not limited to, primary keys, surrogate
980 | keys for temporal databases, foreign keys included in polymorphic relationships,
981 | and keys for key-value pairs in JSON columns and key-value databases.
982 | Applications using a monolithic database may find using database-generated
983 | UUIDs (as opposed to client-generate UUIDs) provides the best UUID monotonicity.
984 | In addition to UUIDs, additional identifiers MAY be used to ensure integrity
985 | and feedback.
986 |
987 |
988 |
989 | # IANA Considerations {#IANA}
990 |
991 | This document has no IANA actions.
992 |
993 |
994 | # Security Considerations {#Security}
995 |
996 | MAC addresses pose inherent security risks and SHOULD not be used within
997 | a UUID.
998 | Instead CSPRNG data SHOULD be selected from a source with sufficient entropy
999 | to ensure guaranteed
1000 | uniqueness among UUID generation. See {{unguessability}} for more information.
1001 |
1002 | Timestamps embedded in the UUID do pose a very small attack surface. The
1003 | timestamp in conjunction with
1004 | an embedded counter does signal the order of creation for a given UUID and
1005 | it's corresponding data but
1006 | does not define anything about the data itself or the application as a whole.
1007 | If UUIDs are required for
1008 | use with any security operation within an application context in any shape
1009 | or form then {{RFC4122}} UUIDv4 SHOULD be utilized.
1010 |
1011 |
1012 | # Acknowledgements {#Acknowledgements}
1013 |
1014 | The authors gratefully acknowledge the contributions of
1015 | Ben Campbell,
1016 | Ben Ramsey,
1017 | Fabio Lima,
1018 | Gonzalo Salgueiro,
1019 | Martin Thomson,
1020 | Murray S. Kucherawy,
1021 | Rick van Rein,
1022 | Rob Wilton,
1023 | Sean Leonard,
1024 | Theodore Y. Ts'o.,
1025 | Robert Kieffer,
1026 | sergeyprokhorenko,
1027 | LiosK
1028 | As well as all of those in the IETF community and on GitHub to who contributed
1029 | to the discussions which resulted in this document.
1030 |
1031 |
1032 | --- back
1033 |
1034 | # Example Code {#example_code}
1035 |
1036 | ## Creating a UUIDv6 Value {#creating_a_uuidv6_value}
1037 |
1038 | This section details a function in C which converts from a UUID version 1
1039 | to version 6:
1040 |
1041 |
1042 | ~~~~
1043 | #include
1044 | #include
1045 | #include
1046 | #include
1047 | #include
1048 |
1049 | /* Converts UUID version 1 to version 6 in place. */
1050 | void uuidv1tov6(uuid_t u) {
1051 |
1052 | uint64_t ut;
1053 | unsigned char *up = (unsigned char *)u;
1054 |
1055 | // load ut with the first 64 bits of the UUID
1056 | ut = ((uint64_t)ntohl(*((uint32_t*)up))) << 32;
1057 | ut |= ((uint64_t)ntohl(*((uint32_t*)&up[4])));
1058 |
1059 | // dance the bit-shift...
1060 | ut =
1061 | ((ut >> 32) & 0x0FFF) | // 12 least significant bits
1062 | (0x6000) | // version number
1063 | ((ut >> 28) & 0x0000000FFFFF0000) | // next 20 bits
1064 | ((ut << 20) & 0x000FFFF000000000) | // next 16 bits
1065 | (ut << 52); // 12 most significant bits
1066 |
1067 | // store back in UUID
1068 | *((uint32_t*)up) = htonl((uint32_t)(ut >> 32));
1069 | *((uint32_t*)&up[4]) = htonl((uint32_t)(ut));
1070 |
1071 | }
1072 | ~~~~
1073 | {: title='UUIDv6 Function in C'}
1074 |
1075 |
1076 | ## Creating a UUIDv7 Value {#creating_a_uuidv7_value}
1077 |
1078 |
1079 | ~~~~
1080 | #include
1081 | #include
1082 | #include
1083 | #include
1084 | #include
1085 |
1086 | // ...
1087 |
1088 | // csprng data source
1089 | FILE *rndf;
1090 | rndf = fopen("/dev/urandom", "r");
1091 | if (rndf == 0) {
1092 | printf("fopen /dev/urandom error\n");
1093 | return 1;
1094 | }
1095 |
1096 | // ...
1097 |
1098 | // generate one UUIDv7E
1099 | uint8_t u[16];
1100 | struct timespec ts;
1101 | int ret;
1102 |
1103 | ret = clock_gettime(CLOCK_REALTIME, &ts);
1104 | if (ret != 0) {
1105 | printf("clock_gettime error: %d\n", ret);
1106 | return 1;
1107 | }
1108 |
1109 | uint64_t tms;
1110 |
1111 | tms = ((uint64_t)ts.tv_sec) * 1000;
1112 | tms += ((uint64_t)ts.tv_nsec) / 1000000;
1113 |
1114 | memset(u, 0, 16);
1115 |
1116 | fread(&u[6], 10, 1, rndf); // fill everything after the timestamp with random bytes
1117 |
1118 | *((uint64_t*)(u)) |= htonll(tms << 16); // shift time into first 48 bits and OR into place
1119 |
1120 | u[8] = 0x80 | (u[8] & 0x3F); // set variant field, top two bits are 1, 0
1121 | u[6] = 0x70 | (u[6] & 0x0F); // set version field, top four bits are 0, 1, 1, 1
1122 | ~~~~
1123 | {: title='UUIDv7 Function in C'}
1124 |
1125 |
1126 | ## Creating a UUIDv8 Value {#creating_a_uuidv8_value}
1127 |
1128 | UUIDv8 will vary greatly from implementation to implementation.
1129 |
1130 | The following example utilizes:
1131 |
1132 |
1133 | * 32 bit custom-epoch timestamp (seconds elapsed since 2020-01-01 00:00:00
1134 | UTC)
1135 |
1136 |
1137 |
1138 | * 16 bit exotic resolution (~15 microsecond) subsecond timestamp encoded using
1139 | the fractional representation
1140 |
1141 |
1142 |
1143 | * 58 bit random number
1144 |
1145 |
1146 |
1147 | * 8 bit application-specific unique node ID
1148 |
1149 |
1150 |
1151 | * 8 bit rolling sequence number
1152 |
1153 |
1154 |
1155 |
1156 | ~~~~
1157 | #include
1158 | #include
1159 |
1160 | int get_random_bytes(uint8_t *buffer, int count) {
1161 | // ...
1162 | }
1163 |
1164 | int generate_uuidv8(uint8_t *uuid, uint8_t node_id) {
1165 | struct timespec tp;
1166 | if (clock_gettime(CLOCK_REALTIME, &tp) != 0)
1167 | return -1; // real-time clock error
1168 |
1169 | // 32 bit biased timestamp (seconds elapsed since 2020-01-01 00:00:00 UTC)
1170 | uint32_t timestamp_sec = tp.tv_sec - 1577836800;
1171 | uuid[0] = timestamp_sec >> 24;
1172 | uuid[1] = timestamp_sec >> 16;
1173 | uuid[2] = timestamp_sec >> 8;
1174 | uuid[3] = timestamp_sec;
1175 |
1176 | // 16 bit subsecond fraction (~15 microsecond resolution)
1177 | uint16_t timestamp_subsec = ((uint64_t)tp.tv_nsec << 16) / 1000000000;
1178 | uuid[4] = timestamp_subsec >> 8;
1179 | uuid[5] = timestamp_subsec;
1180 |
1181 | // 58 bit random number and required ver and var fields
1182 | if (get_random_bytes(&uuid[6], 8) != 0)
1183 | return -1; // random number generator error
1184 | uuid[6] = 0x80 | (uuid[6] & 0x0f);
1185 | uuid[8] = 0x80 | (uuid[8] & 0x3f);
1186 |
1187 | // 8 bit application-specific node ID to guarantee application-wide uniqueness
1188 | uuid[14] = node_id;
1189 |
1190 | // 8 bit rolling sequence number to help ensure process-wide uniqueness
1191 | static uint8_t sequence = 0;
1192 | uuid[15] = sequence++; // NOTE: unprotected from race conditions
1193 |
1194 | return 0;
1195 | }
1196 | ~~~~
1197 | {: title='UUIDv8 Function in C'}
1198 |
1199 |
1200 |
1201 | # Test Vectors {#test_vectors}
1202 |
1203 | Both UUIDv1 and UUIDv6 test vectors utilize the same 60 bit timestamp: 0x1EC9414C232AB00
1204 | (138648505420000000) Tuesday, February 22, 2022 2:22:22.000000 PM GMT-05:00
1205 |
1206 | Both UUIDv1 and UUIDv6 utilize the same values in clk_seq_hi_res, clock_seq_low,
1207 | and node. All of which have been generated with random data.
1208 |
1209 |
1210 | ~~~~
1211 | # Unix Nanosecond precision to Gregorian 100-nanosecond intervals
1212 | gregorian_100_ns = (Unix_64_bit_nanoseconds / 100) + gregorian_Unix_offset
1213 |
1214 | # Gregorian to Unix Offset:
1215 | # The number of 100-ns intervals between the
1216 | # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
1217 | # gregorian_Unix_offset = 0x01b21dd213814000 or 122192928000000000
1218 |
1219 | # Unix 64 bit Nanosecond Timestamp:
1220 | # Unix NS: Tuesday, February 22, 2022 2:22:22 PM GMT-05:00
1221 | # Unix_64_bit_nanoseconds = 0x16D6320C3D4DCC00 or 1645557742000000000
1222 |
1223 | # Work:
1224 | # gregorian_100_ns = (1645557742000000000 / 100) + 122192928000000000
1225 | # (138648505420000000 - 122192928000000000) * 100 = Unix_64_bit_nanoseconds
1226 |
1227 | # Final:
1228 | # gregorian_100_ns = 0x1EC9414C232AB00 or 138648505420000000
1229 |
1230 | # Original: 000111101100100101000001010011000010001100101010101100000000
1231 | # UUIDv1: 11000010001100101010101100000000|1001010000010100|0001|000111101100
1232 | # UUIDv6: 00011110110010010100000101001100|0010001100101010|0110|101100000000
1233 | ~~~~
1234 | {: title='Test Vector Timestamp Pseudo-code'}
1235 |
1236 | ## Example of a UUIDv6 Value {#uuidv6_example}
1237 |
1238 |
1239 | ~~~~
1240 | ----------------------------------------------
1241 | field bits value_hex
1242 | ----------------------------------------------
1243 | time_low 32 0xC232AB00
1244 | time_mid 16 0x9414
1245 | time_hi_and_version 16 0x11EC
1246 | clk_seq_hi_res 8 0xB3
1247 | clock_seq_low 8 0xC8
1248 | node 48 0x9E6BDECED846
1249 | ----------------------------------------------
1250 | total 128
1251 | ----------------------------------------------
1252 | final_hex: C232AB00-9414-11EC-B3C8-9E6BDECED846
1253 | ~~~~
1254 | {: title='UUIDv1 Example Test Vector'}
1255 |
1256 |
1257 | ~~~~
1258 | -----------------------------------------------
1259 | field bits value_hex
1260 | -----------------------------------------------
1261 | time_high 32 0x1EC9414C
1262 | time_mid 16 0x232A
1263 | time_low_and_version 16 0x6B00
1264 | clk_seq_hi_res 8 0xB3
1265 | clock_seq_low 8 0xC8
1266 | node 48 0x9E6BDECED846
1267 | -----------------------------------------------
1268 | total 128
1269 | -----------------------------------------------
1270 | final_hex: 1EC9414C-232A-6B00-B3C8-9E6BDECED846
1271 | ~~~~
1272 | {: title='UUIDv6 Example Test Vector'}
1273 |
1274 |
1275 | ## Example of a UUIDv7 Value {#uuidv7_example}
1276 |
1277 | This example UUIDv7 test vector utilizes a well-known 32 bit Unix epoch with
1278 | additional millisecond precision to fill the first 48 bits
1279 |
1280 | rand_a and rand_b are filled with random data.
1281 |
1282 | The timestamp is Tuesday, February 22, 2022 2:22:22.00 PM GMT-05:00 represented
1283 | as 0x17F22E279B0 or 1645557742000
1284 |
1285 |
1286 | ~~~~
1287 | -------------------------------
1288 | field bits value
1289 | -------------------------------
1290 | unix_ts_ms 48 0x17F22E279B0
1291 | var 4 0x7
1292 | rand_a 12 0xCC3
1293 | var 2 b10
1294 | rand_b 62 0x18C4DC0C0C07398F
1295 | -------------------------------
1296 | total 128
1297 | -------------------------------
1298 | final: 017F22E2-79B0-7CC3-98C4-DC0C0C07398F
1299 | ~~~~
1300 | {: title='UUIDv7 Example Test Vector'}
1301 |
1302 |
1303 | ## Example of a UUIDv8 Value {#uuidv8_example}
1304 |
1305 | This example UUIDv8 test vector utilizes a well-known 64 bit Unix epoch with
1306 | nanosecond precision, truncated to the least-significant, right-most, bits
1307 | to fill the first 48 bits through version.
1308 |
1309 | The next two segments of custom_b and custom_c are are filled with random
1310 | data.
1311 |
1312 | Timestamp is Tuesday, February 22, 2022 2:22:22.000000 PM GMT-05:00 represented
1313 | as 0x16D6320C3D4DCC00 or 1645557742000000000
1314 |
1315 | It should be noted that this example is just to illustrate one scenario for
1316 | UUIDv8. Test vectors will likely be implementation specific and vary greatly
1317 | from this simple example.
1318 |
1319 |
1320 | ~~~~
1321 | -------------------------------
1322 | field bits value
1323 | -------------------------------
1324 | custom_a 48 0x320C3D4DCC00
1325 | ver 4 0x8
1326 | custom_b 12 0x75B
1327 | var 2 b10
1328 | custom_c 62 0xEC932D5F69181C0
1329 | -------------------------------
1330 | total 128
1331 | -------------------------------
1332 | final: 320C3D4D-CC00-875B-8EC9-32D5F69181C0
1333 | ~~~~
1334 | {: title='UUIDv8 Example Test Vector'}
1335 |
1336 |
1337 |
1338 | # Version and Variant Tables {#var_tables}
1339 |
1340 | ## Variant 10xx Versions {#old_var_table}
1341 |
1342 | | Msb0 | Msb1 | Msb2 | Msb3 | Version | Description |
1343 | | 0 | 0 | 0 | 0 | 0 | Unused |
1344 | | 0 | 0 | 0 | 1 | 1 | The Gregorian time-based UUID from in {{RFC4122, Section 4.1.3}} |
1345 | | 0 | 0 | 1 | 0 | 2 | DCE Security version, with embedded POSIX UIDs from {{RFC4122, Section 4.1.3}} |
1346 | | 0 | 0 | 1 | 1 | 3 | The name-based version specified in {{RFC4122, Section 4.1.3}} that uses MD5 hashing. |
1347 | | 0 | 1 | 0 | 0 | 4 | The randomly or pseudo-randomly generated version specified in {{RFC4122, Section 4.1.3}}. |
1348 | | 0 | 1 | 0 | 1 | 5 | The name-based version specified in {{RFC4122, Section 4.1.3}} that uses SHA-1 hashing. |
1349 | | 0 | 1 | 1 | 0 | 6 | Reordered Gregorian time-based UUID specified in this document. |
1350 | | 0 | 1 | 1 | 1 | 7 | Unix Epoch time-based UUID specified in this document. |
1351 | | 1 | 0 | 0 | 0 | 8 | Reserved for custom UUID formats specified in this document. |
1352 | | 1 | 0 | 0 | 1 | 9 | Reserved for future definition. |
1353 | | 1 | 0 | 1 | 0 | 10 | Reserved for future definition. |
1354 | | 1 | 0 | 1 | 1 | 11 | Reserved for future definition. |
1355 | | 1 | 1 | 0 | 0 | 12 | Reserved for future definition. |
1356 | | 1 | 1 | 0 | 1 | 13 | Reserved for future definition. |
1357 | | 1 | 1 | 1 | 0 | 14 | Reserved for future definition. |
1358 | | 1 | 1 | 1 | 1 | 15 | Reserved for future definition. |
1359 | {: title='All UUID variant 10xx (8/9/A/B) version definitions.'}
1360 |
1361 |
1362 |
--------------------------------------------------------------------------------
/editor-files/rfc4122bis.md:
--------------------------------------------------------------------------------
1 | ---
2 | v: 3
3 | cat: std
4 | docname: draft-ietf-uuidrev-rfc4122bis-latest
5 | pi:
6 | compact: 'yes'
7 | text-list-symbols: o*+-
8 | subcompact: 'no'
9 | sortrefs: 'yes'
10 | symrefs: 'yes'
11 | strict: 'yes'
12 | toc: 'yes'
13 | title: A Universally Unique IDentifier (UUID) URN Namespace
14 | abbrev: A UUID URN Namespace
15 | # date: 2005-06
16 | author:
17 | - ins: P. Leach
18 | name: P. Leach
19 | org: Microsoft
20 | - ins: M. Mealling
21 | name: M. Mealling
22 | org: VeriSign, Inc.
23 | - ins: R. Salz
24 | name: R. Salz
25 | org: DataPower Technology, Inc.
26 | normative:
27 | ref-1:
28 | title: Network Computing Architecture
29 | author:
30 | - ins: L. Zahn
31 | name: L. Zahn
32 | org: ''
33 | - ins: T. Dineen
34 | name: T. Dineen
35 | org: ''
36 | - ins: P. Leach
37 | name: P. Leach
38 | org: ''
39 | date: 1990-01
40 | seriesinfo:
41 | ISBN: 0-13-611674-4
42 | ref-2:
43 | title: "DCE: Remote Procedure Call"
44 | rc: Open Group CAE Specification C309
45 | seriesinfo:
46 | ISBN: 1-85912-041-5
47 | date: August 1994
48 | ref-3:
49 | seriesinfo:
50 | ISO/IEC: '9834-8:2004'
51 | ITU-T Rec.: X.667
52 | title: >
53 | Information Technology, "Procedures for the
54 | operation of OSI Registration Authorities: Generation and
55 | registration of Universally Unique Identifiers (UUIDs) and their
56 | use as ASN.1 Object Identifier components"
57 | date: 2004
58 | ref-4: RFC1321
59 | ref-5: RFC4086
60 | ref-6: RFC2141
61 | ref-7: RFC2234
62 | ref-8:
63 | target: http://www.itl.nist.gov/fipspubs/fip180-1.htm
64 | title: Secure Hash Standard
65 | author:
66 | - org: National Institute of Standards and Technology
67 | date: 1995-04
68 | seriesinfo:
69 | FIPS: PUB 180-1
70 |
71 | --- abstract
72 |
73 |
74 | This specification defines a Uniform Resource Name namespace for
75 | UUIDs (Universally Unique IDentifier), also known as GUIDs (Globally
76 | Unique IDentifier). A UUID is 128 bits long, and can guarantee
77 | uniqueness across space and time. UUIDs were originally used in the
78 | Apollo Network Computing System and later in the Open Software
79 | Foundation's (OSF) Distributed Computing Environment (DCE), and then
80 | in Microsoft Windows platforms.
81 |
82 | This specification is derived from the DCE specification with the
83 | kind permission of the OSF (now known as The Open Group).
84 | Information from earlier versions of the DCE specification have been
85 | incorporated into this document.
86 |
87 | --- middle
88 |
89 | # Introduction
90 |
91 | This specification defines a Uniform Resource Name namespace for
92 | UUIDs (Universally Unique IDentifier), also known as GUIDs (Globally
93 | Unique IDentifier). A UUID is 128 bits long, and requires no central
94 | registration process.
95 |
96 | The information here is meant to be a concise guide for those wishing
97 | to implement services using UUIDs as URNs. Nothing in this document
98 | should be construed to override the DCE standards that defined UUIDs.
99 |
100 | There is an ITU-T Recommendation and ISO/IEC Standard [3] that are
101 | derived from earlier versions of this document. Both sets of
102 | specifications have been aligned, and are fully technically
103 | compatible. In addition, a global registration function is being
104 | provided by the Telecommunications Standardisation Bureau of ITU-T;
105 | for details see [](http://www.itu.int/ITU-T/asn1/uuid.html).
106 |
107 |
108 | # Motivation
109 |
110 | One of the main reasons for using UUIDs is that no centralized
111 | authority is required to administer them (although one format uses
112 | IEEE 802 node identifiers, others do not). As a result, generation
113 | on demand can be completely automated, and used for a variety of
114 | purposes. The UUID generation algorithm described here supports very
115 | high allocation rates of up to 10 million per second per machine if
116 | necessary, so that they could even be used as transaction IDs.
117 |
118 | UUIDs are of a fixed size (128 bits) which is reasonably small
119 | compared to other alternatives. This lends itself well to sorting,
120 | ordering, and hashing of all sorts, storing in databases, simple
121 | allocation, and ease of programming in general.
122 |
123 | Since UUIDs are unique and persistent, they make excellent Uniform
124 | Resource Names. The unique ability to generate a new UUID without a
125 | registration process allows for UUIDs to be one of the URNs with the
126 | lowest minting cost.
127 |
128 |
129 | # Namespace Registration Template
130 |
131 | {:vspace}
132 | Namespace ID:
133 | : UUID
134 |
135 | Registration Information:
136 | : Registration date: 2003-10-01
137 |
138 | Declared registrant of the namespace:
139 | : JTC 1/SC6 (ASN.1 Rapporteur Group)
140 |
141 | Declaration of syntactic structure:
142 | : A UUID is an identifier that is unique across both space and time,
143 | with respect to the space of all UUIDs. Since a UUID is a fixed
144 | size and contains a time field, it is possible for values to
145 | rollover (around A.D. 3400, depending on the specific algorithm
146 | used). A UUID can be used for multiple purposes, from tagging
147 | objects with an extremely short lifetime, to reliably identifying
148 | very persistent objects across a network.
149 |
150 | The internal representation of a UUID is a specific sequence of
151 | bits in memory, as described in {{sect-4}}. To accurately
152 | represent a UUID as a URN, it is necessary to convert the bit
153 | sequence to a string representation.
154 |
155 | Each field is treated as an integer and has its value printed as a
156 | zero-filled hexadecimal digit string with the most significant
157 | digit first. The hexadecimal values "a" through "f" are output as
158 | lower case characters and are case insensitive on input.
159 |
160 | The formal definition of the UUID string representation is
161 | provided by the following ABNF {{ref-7}}:
162 |
163 | ~~~~ abnf
164 | UUID = time-low "-" time-mid "-"
165 | time-high-and-version "-"
166 | clock-seq-and-reserved
167 | clock-seq-low "-" node
168 | time-low = 4hexOctet
169 | time-mid = 2hexOctet
170 | time-high-and-version = 2hexOctet
171 | clock-seq-and-reserved = hexOctet
172 | clock-seq-low = hexOctet
173 | node = 6hexOctet
174 | hexOctet = hexDigit hexDigit
175 | hexDigit =
176 | "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" /
177 | "a" / "b" / "c" / "d" / "e" / "f" /
178 | "A" / "B" / "C" / "D" / "E" / "F"
179 | ~~~~
180 |
181 | The following is an example of the string representation of a UUID as
182 | a URN:
183 |
184 | urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6
185 |
186 | Relevant ancillary documentation:
187 | : {{ref-1}}{{ref-2}}
188 |
189 | Identifier uniqueness considerations:
190 | : This document specifies three algorithms to generate UUIDs: the
191 | first leverages the unique values of 802 MAC addresses to
192 | guarantee uniqueness, the second uses pseudo-random number
193 | generators, and the third uses cryptographic hashing and
194 | application-provided text strings. As a result, the UUIDs
195 | generated according to the mechanisms here will be unique from all
196 | other UUIDs that have been or will be assigned.
197 |
198 | Identifier persistence considerations:
199 | : UUIDs are inherently very difficult to resolve in a global sense.
200 | This, coupled with the fact that UUIDs are temporally unique
201 | within their spatial context, ensures that UUIDs will remain as
202 | persistent as possible.
203 |
204 | Process of identifier assignment:
205 | : Generating a UUID does not require that a registration authority
206 | be contacted. One algorithm requires a unique value over space
207 | for each generator. This value is typically an IEEE 802 MAC
208 | address, usually already available on network-connected hosts.
209 | The address can be assigned from an address block obtained from
210 | the IEEE registration authority. If no such address is available,
211 | or privacy concerns make its use undesirable, {{sect-4.5}} specifies
212 | two alternatives. Another approach is to use version 3
213 | or version 4 UUIDs as defined below.
214 |
215 | Process for identifier resolution:
216 | : Since UUIDs are not globally resolvable, this is not applicable.
217 |
218 | Rules for Lexical Equivalence:
219 | : Consider each field of the UUID to be an unsigned integer as shown
220 | in the table in section {{sect-4.1.2}}. Then, to compare a pair of
221 | UUIDs, arithmetically compare the corresponding fields from each
222 | UUID in order of significance and according to their data type.
223 | Two UUIDs are equal if and only if all the corresponding fields
224 | are equal.
225 |
226 | As an implementation note, equality comparison can be performed on
227 | many systems by doing the appropriate byte-order canonicalization,
228 | and then treating the two UUIDs as 128-bit unsigned integers.
229 |
230 | UUIDs, as defined in this document, can also be ordered
231 | lexicographically. For a pair of UUIDs, the first one follows the
232 | second if the most significant field in which the UUIDs differ is
233 | greater for the first UUID. The second precedes the first if the
234 | most significant field in which the UUIDs differ is greater for
235 | the second UUID.
236 |
237 | Conformance with URN Syntax:
238 | : The string representation of a UUID is fully compatible with the
239 | URN syntax. When converting from a bit-oriented, in-memory
240 | representation of a UUID into a URN, care must be taken to
241 | strictly adhere to the byte order issues mentioned in the string
242 | representation section.
243 |
244 | Validation mechanism:
245 | : Apart from determining whether the timestamp portion of the UUID
246 | is in the future and therefore not yet assignable, there is no
247 | mechanism for determining whether a UUID is 'valid'.
248 |
249 | Scope:
250 | : UUIDs are global in scope.
251 |
252 |
253 |
254 | # Specification {#sect-4}
255 |
256 | ## Format
257 | {: id="sect-4.1"}
258 |
259 | The UUID format is 16 octets; some bits of the eight octet variant
260 | field specified below determine finer structure.
261 |
262 | ### Variant
263 | {: id="sect-4.1.1"}
264 |
265 | The variant field determines the layout of the UUID. That is, the
266 | interpretation of all other bits in the UUID depends on the setting
267 | of the bits in the variant field. As such, it could more accurately
268 | be called a type field; we retain the original term for
269 | compatibility. The variant field consists of a variable number of
270 | the most significant bits of octet 8 of the UUID.
271 |
272 | {{table1}} lists the contents of the variant field, where
273 | the letter "x" indicates a "don't-care" value.
274 |
275 | | Msb0 | Msb1 | Msb2 | Description |
276 | | :--: | :--: | :--: | ----------------------------------------------------- |
277 | | 0 | x | x | Reserved, NCS backward compatibility. |
278 | | 1 | 0 | x | The variant specified in this document. |
279 | | 1 | 1 | 0 | Reserved, Microsoft Corporation backward compatibility |
280 | | 1 | 1 | 1 | Reserved for future definition. |
281 | {: #table1}
282 |
283 | Interoperability, in any form, with variants other than the one
284 | defined here is not guaranteed, and is not likely to be an issue in
285 | practice.
286 |
287 |
288 | ### Layout and Byte Order
289 | {: id="sect-4.1.2"}
290 |
291 | To minimize confusion about bit assignments within octets, the UUID
292 | record definition is defined only in terms of fields that are
293 | integral numbers of octets. The fields are presented with the most
294 | significant one first.
295 |
296 | | Field | Data Type | Octet # | " Note |
297 | |---------------------------|-------------------------|---------|---------------------------------------------------------------------|
298 | | time_low | unsigned 32 bit integer | 0-3 | The low field of the timestamp |
299 | | time_mid | unsigned 16 bit integer | 4-5 | The middle field of the timestamp |
300 | | time_hi_and_version | unsigned 16 bit integer | 6-7 | The high field of the timestamp multiplexed with the version number |
301 | | clock_seq_hi_and_reserved | unsigned 8 bit integer | 8 | The high field of the clock sequence multiplexed with the variant |
302 | | clock_seq_low | unsigned 8 bit integer | 9 | The low field of the clock sequence |
303 | | node | unsigned 48 bit integer | 10-15 | The spatially unique node identifier |
304 | {: #table2}
305 |
306 | In the absence of explicit application or presentation protocol
307 | specification to the contrary, a UUID is encoded as a 128-bit object,
308 | as follows:
309 |
310 | The fields are encoded as 16 octets, with the sizes and order of the
311 | fields defined above, and with each field encoded with the Most
312 | Significant Byte first (known as network byte order). Note that the
313 | field names, particularly for multiplexed fields, follow historical
314 | practice.
315 |
316 | ~~~~
317 | 0 1 2 3
318 | 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
319 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
320 | | time_low |
321 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
322 | | time_mid | time_hi_and_version |
323 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
324 | |clk_seq_hi_res | clk_seq_low | node (0-1) |
325 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
326 | | node (2-5) |
327 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
328 | ~~~~
329 |
330 |
331 | ### Version
332 | {: id="sect-4.1.3"}
333 |
334 | The version number is in the most significant 4 bits of the time
335 | stamp (bits 4 through 7 of the time_hi_and_version field).
336 |
337 | {{table3}} lists the currently-defined versions for this
338 | UUID variant.
339 |
340 |
341 |
342 | | Msb0 | Msb1 | Msb2 | Msb3 | Version | Description |
343 | |------|------|------|------|---------|-------------------------------------------------------------------------------|
344 | | 0 | 0 | 0 | 1 | 1 | The time-based version specified in this document. |
345 | | 0 | 0 | 1 | 0 | 2 | DCE Security version, with embedded POSIX UIDs. |
346 | | 0 | 0 | 1 | 1 | 3 | The name-based version specified in this document that uses MD5 hashing. |
347 | | 0 | 1 | 0 | 0 | 4 | The randomly or pseudo-randomly generated version specified in this document. |
348 | | 0 | 1 | 0 | 1 | 5 | The name-based version specified in this document that uses SHA-1 hashing. |
349 | {: #table3}
350 |
351 | The version is more accurately a sub-type; again, we retain the term
352 | for compatibility.
353 |
354 |
355 | ### Timestamp
356 | {: id="sect-4.1.4"}
357 |
358 | The timestamp is a 60-bit value. For UUID version 1, this is
359 | represented by Coordinated Universal Time (UTC) as a count of 100-
360 | nanosecond intervals since 00:00:00.00, 15 October 1582 (the date of
361 | Gregorian reform to the Christian calendar).
362 |
363 | For systems that do not have UTC available, but do have the local
364 | time, they may use that instead of UTC, as long as they do so
365 | consistently throughout the system. However, this is not recommended
366 | since generating the UTC from local time only needs a time zone
367 | offset.
368 |
369 | For UUID version 3 or 5, the timestamp is a 60-bit value constructed
370 | from a name as described in {{sect-4.3}}.
371 |
372 | For UUID version 4, the timestamp is a randomly or pseudo-randomly
373 | generated 60-bit value, as described in {{sect-4.4}}.
374 |
375 |
376 | ### Clock Sequence
377 | {: id="sect-4.1.5"}
378 |
379 | For UUID version 1, the clock sequence is used to help avoid
380 | duplicates that could arise when the clock is set backwards in time
381 | or if the node ID changes.
382 |
383 | If the clock is set backwards, or might have been set backwards
384 | (e.g., while the system was powered off), and the UUID generator can
385 | not be sure that no UUIDs were generated with timestamps larger than
386 | the value to which the clock was set, then the clock sequence has to
387 | be changed. If the previous value of the clock sequence is known, it
388 | can just be incremented; otherwise it should be set to a random or
389 | high-quality pseudo-random value.
390 |
391 | Similarly, if the node ID changes (e.g., because a network card has
392 | been moved between machines), setting the clock sequence to a random
393 | number minimizes the probability of a duplicate due to slight
394 | differences in the clock settings of the machines. If the value of
395 | clock sequence associated with the changed node ID were known, then
396 | the clock sequence could just be incremented, but that is unlikely.
397 |
398 | The clock sequence MUST be originally (i.e., once in the lifetime of
399 | a system) initialized to a random number to minimize the correlation
400 | across systems. This provides maximum protection against node
401 | identifiers that may move or switch from system to system rapidly.
402 | The initial value MUST NOT be correlated to the node identifier.
403 |
404 | For UUID version 3 or 5, the clock sequence is a 14-bit value
405 | constructed from a name as described in {{sect-4.3}}.
406 |
407 | For UUID version 4, clock sequence is a randomly or pseudo-randomly
408 | generated 14-bit value as described in {{sect-4.4}}.
409 |
410 |
411 | ### Node
412 | {: id="sect-4.1.6"}
413 |
414 | For UUID version 1, the node field consists of an IEEE 802 MAC
415 | address, usually the host address. For systems with multiple IEEE
416 | 802 addresses, any available one can be used. The lowest addressed
417 | octet (octet number 10) contains the global/local bit and the
418 | unicast/multicast bit, and is the first octet of the address
419 | transmitted on an 802.3 LAN.
420 |
421 | For systems with no IEEE address, a randomly or pseudo-randomly
422 | generated value may be used; see {{sect-4.5}}. The multicast bit must
423 | be set in such addresses, in order that they will never conflict with
424 | addresses obtained from network cards.
425 |
426 | For UUID version 3 or 5, the node field is a 48-bit value constructed
427 | from a name as described in {{sect-4.3}}.
428 |
429 | For UUID version 4, the node field is a randomly or pseudo-randomly
430 | generated 48-bit value as described in {{sect-4.4}}.
431 |
432 |
433 | ### Nil UUID
434 | {: id="sect-4.1.7"}
435 |
436 | The nil UUID is special form of UUID that is specified to have all
437 | 128 bits set to zero.
438 |
439 |
440 |
441 | ## Algorithms for Creating a Time-Based UUID
442 | {: id="sect-4.2"}
443 |
444 | Various aspects of the algorithm for creating a version 1 UUID are
445 | discussed in the following sections.
446 |
447 | ### Basic Algorithm
448 | {: id="sect-4.2.1"}
449 |
450 | The following algorithm is simple, correct, and inefficient:
451 |
452 | * Obtain a system-wide global lock
453 |
454 | * From a system-wide shared stable store (e.g., a file), read the
455 | UUID generator state: the values of the timestamp, clock sequence,
456 | and node ID used to generate the last UUID.
457 |
458 | * Get the current time as a 60-bit count of 100-nanosecond intervals
459 | since 00:00:00.00, 15 October 1582.
460 |
461 | * Get the current node ID.
462 |
463 | * If the state was unavailable (e.g., non-existent or corrupted), or
464 | the saved node ID is different than the current node ID, generate
465 | a random clock sequence value.
466 |
467 | * If the state was available, but the saved timestamp is later than
468 | the current timestamp, increment the clock sequence value.
469 |
470 | * Save the state (current timestamp, clock sequence, and node ID)
471 | back to the stable store.
472 |
473 | * Release the global lock.
474 |
475 | * Format a UUID from the current timestamp, clock sequence, and node
476 | ID values according to the steps in {{sect-4.2.2}}.
477 |
478 |
479 | If UUIDs do not need to be frequently generated, the above algorithm
480 | may be perfectly adequate. For higher performance requirements,
481 | however, issues with the basic algorithm include:
482 |
483 | * Reading the state from stable storage each time is inefficient.
484 |
485 | * The resolution of the system clock may not be 100-nanoseconds.
486 |
487 | * Writing the state to stable storage each time is inefficient.
488 |
489 | * Sharing the state across process boundaries may be inefficient.
490 |
491 |
492 | Each of these issues can be addressed in a modular fashion by local
493 | improvements in the functions that read and write the state and read
494 | the clock. We address each of them in turn in the following
495 | sections.
496 |
497 | #### Reading Stable Storage
498 | {: id="sect-4.2.1.1"}
499 |
500 | The state only needs to be read from stable storage once at boot
501 | time, if it is read into a system-wide shared volatile store (and
502 | updated whenever the stable store is updated).
503 |
504 | If an implementation does not have any stable store available, then
505 | it can always say that the values were unavailable. This is the
506 | least desirable implementation because it will increase the frequency
507 | of creation of new clock sequence numbers, which increases the
508 | probability of duplicates.
509 |
510 | If the node ID can never change (e.g., the net card is inseparable
511 | from the system), or if any change also reinitializes the clock
512 | sequence to a random value, then instead of keeping it in stable
513 | store, the current node ID may be returned.
514 |
515 |
516 | #### System Clock Resolution
517 | {: id="sect-4.2.1.2"}
518 |
519 | The timestamp is generated from the system time, whose resolution may
520 | be less than the resolution of the UUID timestamp.
521 |
522 | If UUIDs do not need to be frequently generated, the timestamp can
523 | simply be the system time multiplied by the number of 100-nanosecond
524 | intervals per system time interval.
525 |
526 | If a system overruns the generator by requesting too many UUIDs
527 | within a single system time interval, the UUID service MUST either
528 | return an error, or stall the UUID generator until the system clock
529 | catches up.
530 |
531 | A high resolution timestamp can be simulated by keeping a count of
532 | the number of UUIDs that have been generated with the same value of
533 | the system time, and using it to construct the low order bits of the
534 | timestamp. The count will range between zero and the number of
535 | 100-nanosecond intervals per system time interval.
536 |
537 | Note: If the processors overrun the UUID generation frequently,
538 | additional node identifiers can be allocated to the system, which
539 | will permit higher speed allocation by making multiple UUIDs
540 | potentially available for each time stamp value.
541 |
542 |
543 | #### Writing Stable Storage
544 | {: id="sect-4.2.1.3"}
545 |
546 | The state does not always need to be written to stable store every
547 | time a UUID is generated. The timestamp in the stable store can be
548 | periodically set to a value larger than any yet used in a UUID. As
549 | long as the generated UUIDs have timestamps less than that value, and
550 | the clock sequence and node ID remain unchanged, only the shared
551 | volatile copy of the state needs to be updated. Furthermore, if the
552 | timestamp value in stable store is in the future by less than the
553 | typical time it takes the system to reboot, a crash will not cause a
554 | reinitialization of the clock sequence.
555 |
556 |
557 | #### Sharing State Across Processes
558 | {: id="sect-4.2.1.4"}
559 |
560 | If it is too expensive to access shared state each time a UUID is
561 | generated, then the system-wide generator can be implemented to
562 | allocate a block of time stamps each time it is called; a per-
563 | process generator can allocate from that block until it is exhausted.
564 |
565 |
566 |
567 | ### Generation Details
568 | {: id="sect-4.2.2"}
569 |
570 | Version 1 UUIDs are generated according to the following algorithm:
571 |
572 |
573 |
574 | * Determine the values for the UTC-based timestamp and clock
575 | sequence to be used in the UUID, as described in {{sect-4.2.1}}.
576 |
577 | * For the purposes of this algorithm, consider the timestamp to be a
578 | 60-bit unsigned integer and the clock sequence to be a 14-bit
579 | unsigned integer. Sequentially number the bits in a field,
580 | starting with zero for the least significant bit.
581 |
582 | * Set the time_low field equal to the least significant 32 bits
583 | (bits zero through 31) of the timestamp in the same order of
584 | significance.
585 |
586 | * Set the time_mid field equal to bits 32 through 47 from the
587 | timestamp in the same order of significance.
588 |
589 | * Set the 12 least significant bits (bits zero through 11) of the
590 | time_hi_and_version field equal to bits 48 through 59 from the
591 | timestamp in the same order of significance.
592 |
593 | * Set the four most significant bits (bits 12 through 15) of the
594 | time_hi_and_version field to the 4-bit version number
595 | corresponding to the UUID version being created, as shown in the
596 | table above.
597 |
598 | * Set the clock_seq_low field to the eight least significant bits
599 | (bits zero through 7) of the clock sequence in the same order of
600 | significance.
601 |
602 | * Set the 6 least significant bits (bits zero through 5) of the
603 | clock_seq_hi_and_reserved field to the 6 most significant bits
604 | (bits 8 through 13) of the clock sequence in the same order of
605 | significance.
606 |
607 | * Set the two most significant bits (bits 6 and 7) of the
608 | clock_seq_hi_and_reserved to zero and one, respectively.
609 |
610 | * Set the node field to the 48-bit IEEE address in the same order of
611 | significance as the address.
612 |
613 |
614 |
615 |
616 | ## Algorithm for Creating a Name-Based UUID
617 | {: id="sect-4.3"}
618 |
619 | The version 3 or 5 UUID is meant for generating UUIDs from "names"
620 | that are drawn from, and unique within, some "name space". The
621 | concept of name and name space should be broadly construed, and not
622 | limited to textual names. For example, some name spaces are the
623 | domain name system, URLs, ISO Object IDs (OIDs), X.500 Distinguished
624 | Names (DNs), and reserved words in a programming language. The
625 | mechanisms or conventions used for allocating names and ensuring
626 | their uniqueness within their name spaces are beyond the scope of
627 | this specification.
628 |
629 | The requirements for these types of UUIDs are as follows:
630 |
631 | * The UUIDs generated at different times from the same name in the
632 | same namespace MUST be equal.
633 |
634 | * The UUIDs generated from two different names in the same namespace
635 | should be different (with very high probability).
636 |
637 | * The UUIDs generated from the same name in two different namespaces
638 | should be different with (very high probability).
639 |
640 | * If two UUIDs that were generated from names are equal, then they
641 | were generated from the same name in the same namespace (with very
642 | high probability).
643 |
644 |
645 | The algorithm for generating a UUID from a name and a name space are
646 | as follows:
647 |
648 | * Allocate a UUID to use as a "name space ID" for all UUIDs
649 | generated from names in that name space; see Appendix C for some
650 | pre-defined values.
651 |
652 | * Choose either MD5 {{ref-4}} or SHA-1 {{ref-8}} as the hash algorithm; If
653 | backward compatibility is not an issue, SHA-1 is preferred.
654 |
655 | * Convert the name to a canonical sequence of octets (as defined by
656 | the standards or conventions of its name space); put the name
657 | space ID in network byte order.
658 |
659 | * Compute the hash of the name space ID concatenated with the name.
660 |
661 | * Set octets zero through 3 of the time_low field to octets zero
662 | through 3 of the hash.
663 |
664 | * Set octets zero and one of the time_mid field to octets 4 and 5 of
665 | the hash.
666 |
667 | * Set octets zero and one of the time_hi_and_version field to octets
668 | 6 and 7 of the hash.
669 |
670 | * Set the four most significant bits (bits 12 through 15) of the
671 | time_hi_and_version field to the appropriate 4-bit version number
672 | from {{sect-4.1.3}}.
673 |
674 | * Set the clock_seq_hi_and_reserved field to octet 8 of the hash.
675 |
676 | * Set the two most significant bits (bits 6 and 7) of the
677 | clock_seq_hi_and_reserved to zero and one, respectively.
678 |
679 | * Set the clock_seq_low field to octet 9 of the hash.
680 |
681 | * Set octets zero through five of the node field to octets 10
682 | through 15 of the hash.
683 |
684 | * Convert the resulting UUID to local byte order.
685 |
686 |
687 |
688 | ## Algorithms for Creating a UUID from Truly Random or Pseudo-Random Numbers
689 | {: id="sect-4.4"}
690 |
691 | The version 4 UUID is meant for generating UUIDs from truly-random or
692 | pseudo-random numbers.
693 |
694 | The algorithm is as follows:
695 |
696 | * Set the two most significant bits (bits 6 and 7) of the
697 | clock_seq_hi_and_reserved to zero and one, respectively.
698 |
699 | * Set the four most significant bits (bits 12 through 15) of the
700 | time_hi_and_version field to the 4-bit version number from {{sect-4.1.3}}.
701 |
702 | * Set all the other bits to randomly (or pseudo-randomly) chosen
703 | values.
704 |
705 |
706 | See {{sect-4.5}} for a discussion on random numbers.
707 |
708 |
709 | ## Node IDs that Do Not Identify the Host
710 | {: id="sect-4.5"}
711 |
712 | This section describes how to generate a version 1 UUID if an IEEE
713 | 802 address is not available, or its use is not desired.
714 |
715 | One approach is to contact the IEEE and get a separate block of
716 | addresses. At the time of writing, the application could be found at
717 | [](http://standards.ieee.org/regauth/oui/pilot-ind.html), and the cost
718 | was US$550.
719 |
720 | A better solution is to obtain a 47-bit cryptographic quality random
721 | number and use it as the low 47 bits of the node ID, with the least
722 | significant bit of the first octet of the node ID set to one. This
723 | bit is the unicast/multicast bit, which will never be set in IEEE 802
724 | addresses obtained from network cards. Hence, there can never be a
725 | conflict between UUIDs generated by machines with and without network
726 | cards. (Recall that the IEEE 802 spec talks about transmission
727 | order, which is the opposite of the in-memory representation that is
728 | discussed in this document.)
729 |
730 | For compatibility with earlier specifications, note that this
731 | document uses the unicast/multicast bit, instead of the arguably more
732 | correct local/global bit.
733 |
734 | Advice on generating cryptographic-quality random numbers can be
735 | found in RFC1750 [5].
736 |
737 | In addition, items such as the computer's name and the name of the
738 | operating system, while not strictly speaking random, will help
739 | differentiate the results from those obtained by other systems.
740 |
741 | The exact algorithm to generate a node ID using these data is system
742 | specific, because both the data available and the functions to obtain
743 | them are often very system specific. A generic approach, however, is
744 | to accumulate as many sources as possible into a buffer, use a
745 | message digest such as MD5 {{ref-4}} or SHA-1 {{ref-8}}, take an arbitrary 6
746 | bytes from the hash value, and set the multicast bit as described
747 | above.
748 |
749 |
750 |
751 | # Community Considerations
752 |
753 | The use of UUIDs is extremely pervasive in computing. They comprise
754 | the core identifier infrastructure for many operating systems
755 | (Microsoft Windows) and applications (the Mozilla browser) and in
756 | many cases, become exposed to the Web in many non-standard ways.
757 |
758 | This specification attempts to standardize that practice as openly as
759 | possible and in a way that attempts to benefit the entire Internet.
760 |
761 |
762 | # Security Considerations
763 |
764 | Do not assume that UUIDs are hard to guess; they should not be used
765 | as security capabilities (identifiers whose mere possession grants
766 | access), for example. A predictable random number source will
767 | exacerbate the situation.
768 |
769 | Do not assume that it is easy to determine if a UUID has been
770 | slightly transposed in order to redirect a reference to another
771 | object. Humans do not have the ability to easily check the integrity
772 | of a UUID by simply glancing at it.
773 |
774 | Distributed applications generating UUIDs at a variety of hosts must
775 | be willing to rely on the random number source at all hosts. If this
776 | is not feasible, the namespace variant should be used.
777 |
778 |
779 | --- back
780 |
781 | # Sample Implementation
782 |
783 | This implementation consists of 5 files: uuid.h, uuid.c, sysdep.h,
784 | sysdep.c and utest.c. The uuid.\* files are the system independent
785 | implementation of the UUID generation algorithms described above,
786 | with all the optimizations described above except efficient state
787 | sharing across processes included. The code has been tested on Linux
788 | (Red Hat 4.0) with GCC (2.7.2), and Windows NT 4.0 with VC++ 5.0.
789 | The code assumes 64-bit integer support, which makes it much clearer.
790 |
791 | All the following source files should have the following copyright
792 | notice included:
793 |
794 | copyrt.h
795 |
796 | ~~~
797 |
798 | /*
799 | ** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
800 | ** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
801 | ** Digital Equipment Corporation, Maynard, Mass.
802 | ** Copyright (c) 1998 Microsoft.
803 | ** To anyone who acknowledges that this file is provided "AS IS"
804 | ** without any express or implied warranty: permission to use, copy,
805 | ** modify, and distribute this file for any purpose is hereby
806 | ** granted without fee, provided that the above copyright notices and
807 | ** this notice appears in all source code copies, and that none of
808 | ** the names of Open Software Foundation, Inc., Hewlett-Packard
809 | ** Company, or Digital Equipment Corporation be used in advertising
810 | ** or publicity pertaining to distribution of the software without
811 | ** specific, written prior permission. Neither Open Software
812 | ** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
813 | ** Equipment Corporation makes any representations about the
814 | ** suitability of this software for any purpose.
815 | */
816 |
817 | ~~~
818 |
819 | uuid.h
820 |
821 | ~~~
822 | #include "copyrt.h"
823 | #undef uuid_t
824 | typedef struct {
825 | unsigned32 time_low;
826 | unsigned16 time_mid;
827 | unsigned16 time_hi_and_version;
828 | unsigned8 clock_seq_hi_and_reserved;
829 | unsigned8 clock_seq_low;
830 | byte node[6];
831 | } uuid_t;
832 |
833 | /* uuid_create -- generate a UUID */
834 | int uuid_create(uuid_t * uuid);
835 |
836 | /* uuid_create_md5_from_name -- create a version 3 (MD5) UUID using a
837 | "name" from a "name space" */
838 | void uuid_create_md5_from_name(
839 | uuid_t *uuid, /* resulting UUID */
840 | uuid_t nsid, /* UUID of the namespace */
841 | void *name, /* the name from which to generate a UUID */
842 | int namelen /* the length of the name */
843 | );
844 |
845 | /* uuid_create_sha1_from_name -- create a version 5 (SHA-1) UUID
846 | using a "name" from a "name space" */
847 | void uuid_create_sha1_from_name(
848 |
849 | uuid_t *uuid, /* resulting UUID */
850 | uuid_t nsid, /* UUID of the namespace */
851 | void *name, /* the name from which to generate a UUID */
852 | int namelen /* the length of the name */
853 | );
854 |
855 | /* uuid_compare -- Compare two UUID's "lexically" and return
856 | -1 u1 is lexically before u2
857 | 0 u1 is equal to u2
858 | 1 u1 is lexically after u2
859 | Note that lexical ordering is not temporal ordering!
860 | */
861 | int uuid_compare(uuid_t *u1, uuid_t *u2);
862 | ~~~
863 |
864 | uuid.c
865 |
866 | ~~~
867 | #include "copyrt.h"
868 | #include
869 | #include
870 | #include
871 | #include
872 | #include "sysdep.h"
873 | #include "uuid.h"
874 |
875 | /* various forward declarations */
876 | static int read_state(unsigned16 *clockseq, uuid_time_t *timestamp,
877 | uuid_node_t *node);
878 | static void write_state(unsigned16 clockseq, uuid_time_t timestamp,
879 | uuid_node_t node);
880 | static void format_uuid_v1(uuid_t *uuid, unsigned16 clockseq,
881 | uuid_time_t timestamp, uuid_node_t node);
882 | static void format_uuid_v3or5(uuid_t *uuid, unsigned char hash[16],
883 | int v);
884 | static void get_current_time(uuid_time_t *timestamp);
885 | static unsigned16 true_random(void);
886 |
887 | /* uuid_create -- generator a UUID */
888 | int uuid_create(uuid_t *uuid)
889 | {
890 | uuid_time_t timestamp, last_time;
891 | unsigned16 clockseq;
892 | uuid_node_t node;
893 | uuid_node_t last_node;
894 | int f;
895 |
896 | /* acquire system-wide lock so we're alone */
897 | LOCK;
898 | /* get time, node ID, saved state from non-volatile storage */
899 | get_current_time(×tamp);
900 | get_ieee_node_identifier(&node);
901 | f = read_state(&clockseq, &last_time, &last_node);
902 |
903 | /* if no NV state, or if clock went backwards, or node ID
904 | changed (e.g., new network card) change clockseq */
905 | if (!f || memcmp(&node, &last_node, sizeof node))
906 | clockseq = true_random();
907 | else if (timestamp < last_time)
908 | clockseq++;
909 |
910 | /* save the state for next time */
911 | write_state(clockseq, timestamp, node);
912 |
913 | UNLOCK;
914 |
915 | /* stuff fields into the UUID */
916 | format_uuid_v1(uuid, clockseq, timestamp, node);
917 | return 1;
918 | }
919 |
920 | /* format_uuid_v1 -- make a UUID from the timestamp, clockseq,
921 | and node ID */
922 | void format_uuid_v1(uuid_t* uuid, unsigned16 clock_seq,
923 | uuid_time_t timestamp, uuid_node_t node)
924 | {
925 | /* Construct a version 1 uuid with the information we've gathered
926 | plus a few constants. */
927 | uuid->time_low = (unsigned long)(timestamp & 0xFFFFFFFF);
928 | uuid->time_mid = (unsigned short)((timestamp >> 32) & 0xFFFF);
929 | uuid->time_hi_and_version =
930 | (unsigned short)((timestamp >> 48) & 0x0FFF);
931 | uuid->time_hi_and_version |= (1 << 12);
932 | uuid->clock_seq_low = clock_seq & 0xFF;
933 | uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8;
934 | uuid->clock_seq_hi_and_reserved |= 0x80;
935 | memcpy(&uuid->node, &node, sizeof uuid->node);
936 | }
937 |
938 | /* data type for UUID generator persistent state */
939 | typedef struct {
940 | uuid_time_t ts; /* saved timestamp */
941 | uuid_node_t node; /* saved node ID */
942 | unsigned16 cs; /* saved clock sequence */
943 | } uuid_state;
944 |
945 | static uuid_state st;
946 |
947 | /* read_state -- read UUID generator state from non-volatile store */
948 | int read_state(unsigned16 *clockseq, uuid_time_t *timestamp,
949 | uuid_node_t *node)
950 | {
951 | static int inited = 0;
952 | FILE *fp;
953 |
954 | /* only need to read state once per boot */
955 | if (!inited) {
956 | fp = fopen("state", "rb");
957 | if (fp == NULL)
958 | return 0;
959 | fread(&st, sizeof st, 1, fp);
960 | fclose(fp);
961 | inited = 1;
962 | }
963 | *clockseq = st.cs;
964 | *timestamp = st.ts;
965 | *node = st.node;
966 | return 1;
967 | }
968 |
969 | /* write_state -- save UUID generator state back to non-volatile
970 | storage */
971 | void write_state(unsigned16 clockseq, uuid_time_t timestamp,
972 | uuid_node_t node)
973 | {
974 | static int inited = 0;
975 | static uuid_time_t next_save;
976 | FILE* fp;
977 |
978 | if (!inited) {
979 | next_save = timestamp;
980 | inited = 1;
981 | }
982 |
983 | /* always save state to volatile shared state */
984 | st.cs = clockseq;
985 | st.ts = timestamp;
986 | st.node = node;
987 | if (timestamp >= next_save) {
988 | fp = fopen("state", "wb");
989 | fwrite(&st, sizeof st, 1, fp);
990 | fclose(fp);
991 | /* schedule next save for 10 seconds from now */
992 | next_save = timestamp + (10 * 10 * 1000 * 1000);
993 | }
994 | }
995 |
996 | /* get-current_time -- get time as 60-bit 100ns ticks since UUID epoch.
997 | Compensate for the fact that real clock resolution is
998 | less than 100ns. */
999 | void get_current_time(uuid_time_t *timestamp)
1000 | {
1001 | static int inited = 0;
1002 | static uuid_time_t time_last;
1003 | static unsigned16 uuids_this_tick;
1004 | uuid_time_t time_now;
1005 |
1006 | if (!inited) {
1007 | get_system_time(&time_now);
1008 | uuids_this_tick = UUIDS_PER_TICK;
1009 | inited = 1;
1010 | }
1011 |
1012 | for ( ; ; ) {
1013 | get_system_time(&time_now);
1014 |
1015 | /* if clock reading changed since last UUID generated, */
1016 | if (time_last != time_now) {
1017 | /* reset count of uuids gen'd with this clock reading */
1018 | uuids_this_tick = 0;
1019 | time_last = time_now;
1020 | break;
1021 | }
1022 | if (uuids_this_tick < UUIDS_PER_TICK) {
1023 | uuids_this_tick++;
1024 | break;
1025 | }
1026 |
1027 | /* going too fast for our clock; spin */
1028 | }
1029 | /* add the count of uuids to low order bits of the clock reading */
1030 | *timestamp = time_now + uuids_this_tick;
1031 | }
1032 |
1033 | /* true_random -- generate a crypto-quality random number.
1034 | **This sample doesn't do that.** */
1035 | static unsigned16 true_random(void)
1036 | {
1037 | static int inited = 0;
1038 | uuid_time_t time_now;
1039 |
1040 | if (!inited) {
1041 | get_system_time(&time_now);
1042 | time_now = time_now / UUIDS_PER_TICK;
1043 | srand((unsigned int)
1044 | (((time_now >> 32) ^ time_now) & 0xffffffff));
1045 | inited = 1;
1046 | }
1047 |
1048 | return rand();
1049 | }
1050 |
1051 | /* uuid_create_md5_from_name -- create a version 3 (MD5) UUID using a
1052 | "name" from a "name space" */
1053 | void uuid_create_md5_from_name(uuid_t *uuid, uuid_t nsid, void *name,
1054 | int namelen)
1055 | {
1056 | MD5_CTX c;
1057 | unsigned char hash[16];
1058 | uuid_t net_nsid;
1059 |
1060 | /* put name space ID in network byte order so it hashes the same
1061 | no matter what endian machine we're on */
1062 | net_nsid = nsid;
1063 | net_nsid.time_low = htonl(net_nsid.time_low);
1064 | net_nsid.time_mid = htons(net_nsid.time_mid);
1065 | net_nsid.time_hi_and_version = htons(net_nsid.time_hi_and_version);
1066 |
1067 | MD5Init(&c);
1068 | MD5Update(&c, &net_nsid, sizeof net_nsid);
1069 | MD5Update(&c, name, namelen);
1070 | MD5Final(hash, &c);
1071 |
1072 | /* the hash is in network byte order at this point */
1073 | format_uuid_v3or5(uuid, hash, 3);
1074 | }
1075 |
1076 | void uuid_create_sha1_from_name(uuid_t *uuid, uuid_t nsid, void *name,
1077 | int namelen)
1078 | {
1079 | SHA_CTX c;
1080 | unsigned char hash[20];
1081 | uuid_t net_nsid;
1082 |
1083 | /* put name space ID in network byte order so it hashes the same
1084 | no matter what endian machine we're on */
1085 | net_nsid = nsid;
1086 | net_nsid.time_low = htonl(net_nsid.time_low);
1087 | net_nsid.time_mid = htons(net_nsid.time_mid);
1088 | net_nsid.time_hi_and_version = htons(net_nsid.time_hi_and_version);
1089 |
1090 | SHA1_Init(&c);
1091 | SHA1_Update(&c, &net_nsid, sizeof net_nsid);
1092 | SHA1_Update(&c, name, namelen);
1093 | SHA1_Final(hash, &c);
1094 |
1095 | /* the hash is in network byte order at this point */
1096 | format_uuid_v3or5(uuid, hash, 5);
1097 | }
1098 |
1099 | /* format_uuid_v3or5 -- make a UUID from a (pseudo)random 128-bit
1100 | number */
1101 | void format_uuid_v3or5(uuid_t *uuid, unsigned char hash[16], int v)
1102 | {
1103 | /* convert UUID to local byte order */
1104 | memcpy(uuid, hash, sizeof *uuid);
1105 | uuid->time_low = ntohl(uuid->time_low);
1106 | uuid->time_mid = ntohs(uuid->time_mid);
1107 | uuid->time_hi_and_version = ntohs(uuid->time_hi_and_version);
1108 |
1109 | /* put in the variant and version bits */
1110 | uuid->time_hi_and_version &= 0x0FFF;
1111 | uuid->time_hi_and_version |= (v << 12);
1112 | uuid->clock_seq_hi_and_reserved &= 0x3F;
1113 | uuid->clock_seq_hi_and_reserved |= 0x80;
1114 | }
1115 |
1116 | /* uuid_compare -- Compare two UUID's "lexically" and return */
1117 | #define CHECK(f1, f2) if (f1 != f2) return f1 < f2 ? -1 : 1;
1118 | int uuid_compare(uuid_t *u1, uuid_t *u2)
1119 | {
1120 | int i;
1121 |
1122 | CHECK(u1->time_low, u2->time_low);
1123 | CHECK(u1->time_mid, u2->time_mid);
1124 | CHECK(u1->time_hi_and_version, u2->time_hi_and_version);
1125 | CHECK(u1->clock_seq_hi_and_reserved, u2->clock_seq_hi_and_reserved);
1126 | CHECK(u1->clock_seq_low, u2->clock_seq_low)
1127 | for (i = 0; i < 6; i++) {
1128 | if (u1->node[i] < u2->node[i])
1129 | return -1;
1130 | if (u1->node[i] > u2->node[i])
1131 | return 1;
1132 | }
1133 | return 0;
1134 | }
1135 | #undef CHECK
1136 | ~~~
1137 |
1138 | sysdep.h
1139 |
1140 | ~~~
1141 |
1142 | #include "copyrt.h"
1143 | /* remove the following define if you aren't running WIN32 */
1144 | #define WININC 0
1145 |
1146 | #ifdef WININC
1147 | #include
1148 | #else
1149 | #include
1150 | #include
1151 | #include
1152 | #endif
1153 |
1154 | #include "global.h"
1155 | /* change to point to where MD5 .h's live; RFC 1321 has sample
1156 | implementation */
1157 | #include "md5.h"
1158 |
1159 | /* set the following to the number of 100ns ticks of the actual
1160 | resolution of your system's clock */
1161 | #define UUIDS_PER_TICK 1024
1162 |
1163 | /* Set the following to a calls to get and release a global lock */
1164 | #define LOCK
1165 | #define UNLOCK
1166 |
1167 | typedef unsigned long unsigned32;
1168 | typedef unsigned short unsigned16;
1169 | typedef unsigned char unsigned8;
1170 | typedef unsigned char byte;
1171 |
1172 | /* Set this to what your compiler uses for 64-bit data type */
1173 | #ifdef WININC
1174 | #define unsigned64_t unsigned __int64
1175 | #define I64(C) C
1176 | #else
1177 | #define unsigned64_t unsigned long long
1178 | #define I64(C) C##LL
1179 | #endif
1180 |
1181 | typedef unsigned64_t uuid_time_t;
1182 | typedef struct {
1183 | char nodeID[6];
1184 | } uuid_node_t;
1185 |
1186 | void get_ieee_node_identifier(uuid_node_t *node);
1187 | void get_system_time(uuid_time_t *uuid_time);
1188 | void get_random_info(char seed[16]);
1189 | ~~~
1190 |
1191 | sysdep.c
1192 |
1193 | ~~~
1194 | #include "copyrt.h"
1195 | #include
1196 | #include "sysdep.h"
1197 |
1198 | /* system dependent call to get IEEE node ID.
1199 | This sample implementation generates a random node ID. */
1200 | void get_ieee_node_identifier(uuid_node_t *node)
1201 | {
1202 | static inited = 0;
1203 | static uuid_node_t saved_node;
1204 | char seed[16];
1205 | FILE *fp;
1206 |
1207 | if (!inited) {
1208 | fp = fopen("nodeid", "rb");
1209 | if (fp) {
1210 | fread(&saved_node, sizeof saved_node, 1, fp);
1211 | fclose(fp);
1212 | }
1213 | else {
1214 | get_random_info(seed);
1215 | seed[0] |= 0x01;
1216 | memcpy(&saved_node, seed, sizeof saved_node);
1217 | fp = fopen("nodeid", "wb");
1218 | if (fp) {
1219 | fwrite(&saved_node, sizeof saved_node, 1, fp);
1220 | fclose(fp);
1221 | }
1222 | }
1223 | inited = 1;
1224 | }
1225 |
1226 | *node = saved_node;
1227 | }
1228 |
1229 | /* system dependent call to get the current system time. Returned as
1230 | 100ns ticks since UUID epoch, but resolution may be less than
1231 | 100ns. */
1232 | #ifdef _WINDOWS_
1233 |
1234 | void get_system_time(uuid_time_t *uuid_time)
1235 | {
1236 | ULARGE_INTEGER time;
1237 |
1238 | /* NT keeps time in FILETIME format which is 100ns ticks since
1239 | Jan 1, 1601. UUIDs use time in 100ns ticks since Oct 15, 1582.
1240 | The difference is 17 Days in Oct + 30 (Nov) + 31 (Dec)
1241 | + 18 years and 5 leap days. */
1242 | GetSystemTimeAsFileTime((FILETIME *)&time);
1243 | time.QuadPart +=
1244 |
1245 | (unsigned __int64) (1000*1000*10) // seconds
1246 | * (unsigned __int64) (60 * 60 * 24) // days
1247 | * (unsigned __int64) (17+30+31+365*18+5); // # of days
1248 | *uuid_time = time.QuadPart;
1249 | }
1250 |
1251 | /* Sample code, not for use in production; see RFC 1750 */
1252 | void get_random_info(char seed[16])
1253 | {
1254 | MD5_CTX c;
1255 | struct {
1256 | MEMORYSTATUS m;
1257 | SYSTEM_INFO s;
1258 | FILETIME t;
1259 | LARGE_INTEGER pc;
1260 | DWORD tc;
1261 | DWORD l;
1262 | char hostname[MAX_COMPUTERNAME_LENGTH + 1];
1263 | } r;
1264 |
1265 | MD5Init(&c);
1266 | GlobalMemoryStatus(&r.m);
1267 | GetSystemInfo(&r.s);
1268 | GetSystemTimeAsFileTime(&r.t);
1269 | QueryPerformanceCounter(&r.pc);
1270 | r.tc = GetTickCount();
1271 | r.l = MAX_COMPUTERNAME_LENGTH + 1;
1272 | GetComputerName(r.hostname, &r.l);
1273 | MD5Update(&c, &r, sizeof r);
1274 | MD5Final(seed, &c);
1275 | }
1276 |
1277 | #else
1278 |
1279 | void get_system_time(uuid_time_t *uuid_time)
1280 | {
1281 | struct timeval tp;
1282 |
1283 | gettimeofday(&tp, (struct timezone *)0);
1284 |
1285 | /* Offset between UUID formatted times and Unix formatted times.
1286 | UUID UTC base time is October 15, 1582.
1287 | Unix base time is January 1, 1970.*/
1288 | *uuid_time = ((unsigned64)tp.tv_sec * 10000000)
1289 | + ((unsigned64)tp.tv_usec * 10)
1290 | + I64(0x01B21DD213814000);
1291 | }
1292 |
1293 | /* Sample code, not for use in production; see RFC 1750 */
1294 | void get_random_info(char seed[16])
1295 | {
1296 | MD5_CTX c;
1297 | struct {
1298 | struct sysinfo s;
1299 | struct timeval t;
1300 | char hostname[257];
1301 | } r;
1302 |
1303 | MD5Init(&c);
1304 | sysinfo(&r.s);
1305 | gettimeofday(&r.t, (struct timezone *)0);
1306 | gethostname(r.hostname, 256);
1307 | MD5Update(&c, &r, sizeof r);
1308 | MD5Final(seed, &c);
1309 | }
1310 |
1311 | #endif
1312 | ~~~
1313 |
1314 | utest.c
1315 |
1316 | ~~~
1317 | #include "copyrt.h"
1318 | #include "sysdep.h"
1319 | #include
1320 | #include "uuid.h"
1321 |
1322 | uuid_t NameSpace_DNS = { /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 */
1323 | 0x6ba7b810,
1324 | 0x9dad,
1325 | 0x11d1,
1326 | 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
1327 | };
1328 |
1329 | /* puid -- print a UUID */
1330 | void puid(uuid_t u)
1331 | {
1332 | int i;
1333 |
1334 | printf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", u.time_low, u.time_mid,
1335 | u.time_hi_and_version, u.clock_seq_hi_and_reserved,
1336 | u.clock_seq_low);
1337 | for (i = 0; i < 6; i++)
1338 | printf("%2.2x", u.node[i]);
1339 | printf("\n");
1340 | }
1341 |
1342 | /* Simple driver for UUID generator */
1343 | void main(int argc, char **argv)
1344 | {
1345 | uuid_t u;
1346 | int f;
1347 |
1348 | uuid_create(&u);
1349 | printf("uuid_create(): "); puid(u);
1350 |
1351 | f = uuid_compare(&u, &u);
1352 | printf("uuid_compare(u,u): %d\n", f); /* should be 0 */
1353 | f = uuid_compare(&u, &NameSpace_DNS);
1354 | printf("uuid_compare(u, NameSpace_DNS): %d\n", f); /* s.b. 1 */
1355 | f = uuid_compare(&NameSpace_DNS, &u);
1356 | printf("uuid_compare(NameSpace_DNS, u): %d\n", f); /* s.b. -1 */
1357 | uuid_create_md5_from_name(&u, NameSpace_DNS, "www.widgets.com", 15);
1358 | printf("uuid_create_md5_from_name(): "); puid(u);
1359 | }
1360 | ~~~
1361 |
1362 | # Sample Output of utest
1363 |
1364 | ~~~
1365 | uuid_create(): 7d444840-9dc0-11d1-b245-5ffdce74fad2
1366 | uuid_compare(u,u): 0
1367 | uuid_compare(u, NameSpace_DNS): 1
1368 | uuid_compare(NameSpace_DNS, u): -1
1369 | uuid_create_md5_from_name(): e902893a-9d22-3c7e-a7b8-d6e313b71d9f
1370 | ~~~
1371 |
1372 |
1373 |
1374 |
1375 | # Some Name Space IDs
1376 |
1377 | This appendix lists the name space IDs for some potentially
1378 | interesting name spaces, as initialized C structures and in the
1379 | string representation defined above.
1380 |
1381 | ~~~
1382 | /* Name string is a fully-qualified domain name */
1383 | uuid_t NameSpace_DNS = { /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 */
1384 | 0x6ba7b810,
1385 | 0x9dad,
1386 | 0x11d1,
1387 | 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
1388 | };
1389 |
1390 | /* Name string is a URL */
1391 | uuid_t NameSpace_URL = { /* 6ba7b811-9dad-11d1-80b4-00c04fd430c8 */
1392 | 0x6ba7b811,
1393 | 0x9dad,
1394 | 0x11d1,
1395 | 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
1396 | };
1397 |
1398 | /* Name string is an ISO OID */
1399 | uuid_t NameSpace_OID = { /* 6ba7b812-9dad-11d1-80b4-00c04fd430c8 */
1400 | 0x6ba7b812,
1401 | 0x9dad,
1402 | 0x11d1,
1403 | 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
1404 | };
1405 |
1406 | /* Name string is an X.500 DN (in DER or a text output format) */
1407 | uuid_t NameSpace_X500 = { /* 6ba7b814-9dad-11d1-80b4-00c04fd430c8 */
1408 | 0x6ba7b814,
1409 | 0x9dad,
1410 | 0x11d1,
1411 | 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
1412 | };
1413 | ~~~
1414 |
1415 |
1416 | # Acknowledgments
1417 | {:unnumbered}
1418 |
1419 | This document draws heavily on the OSF DCE specification for UUIDs.
1420 | Ted Ts'o provided helpful comments, especially on the byte ordering
1421 | section which we mostly plagiarized from a proposed wording he
1422 | supplied (all errors in that section are our responsibility,
1423 | however).
1424 |
1425 | We are also grateful to the careful reading and bit-twiddling of Ralf
1426 | S. Engelschall, John Larmouth, and Paul Thorpe. Professor Larmouth
1427 | was also invaluable in achieving coordination with ISO/IEC.
1428 |
1429 |
--------------------------------------------------------------------------------
/editor-files/sed-css-replace.md:
--------------------------------------------------------------------------------
1 | ### Replace inline CSS with css from /docs/better-rfc.css
2 | ```
3 | cat draft-ietf-uuidrev-rfc4122bis.html | sed '/