├── .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
  1. */ 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
  2. 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 '/