192

I have code that looks like this:

u := make([]byte, 16)
_, err := rand.Read(u)
if err != nil {
    return
}

u[8] = (u[8] | 0x80) & 0xBF // what does this do?
u[6] = (u[6] | 0x40) & 0x4F // what does this do?

return hex.EncodeToString(u)

It returns a string with a length of 32, but I don't think it is a valid UUID. If it is a real UUID, why is it a UUID, and what is the purpose of the code that modifies the value of u[8] and u[6]?

Is there a better way of generating UUIDs?

informatik01
  • 16,038
  • 10
  • 74
  • 104
hardPass
  • 19,033
  • 19
  • 40
  • 42

15 Answers15

199

There is an official implementation by Google: https://github.com/google/uuid

Generating a version 4 UUID works like this:

package main

import (
    "fmt"
    "github.com/google/uuid"
)

func main() {
    id := uuid.New()
    fmt.Println(id.String())
}

Try it here: https://play.golang.org/p/6YPi1djUMj9

shutefan
  • 6,156
  • 8
  • 23
  • 23
  • 4
    The [godoc](https://godoc.org/github.com/google/uuid#New) recommends using `New()` and it is equivalent to `uuid.Must(uuid.NewRandom())` – Jim May 20 '19 at 21:58
  • @Jim: you're right! I updated my answer accordingly. – shutefan May 20 '19 at 22:39
  • 3
    Note that New() may "fatal" (which is okay in some cases). In cases you don't want your program to fatal just use uuid.NewRandom() - which returns a UUID and an error. – Tomer Jun 28 '19 at 12:54
  • @Tomer: true! Though I wonder under which circumstances this would actually happen. This is the relevant part of the code: https://github.com/google/uuid/blob/c2e93f3ae59f2904160ceaab466009f965df46d6/version4.go#L35 By default the reader is a `rand.Reader`. I'm not sure if that one would ever return an error or if this can only happen with a custom Reader... – shutefan Jun 28 '19 at 15:44
  • 1
    Hi @shutefan - I agree that it may be rare. rand.Reader calls Kernel functions (https://golang.org/src/crypto/rand/rand.go). These may fail in certain scenarios. – Tomer Jun 29 '19 at 19:52
  • Note that Google's work is partially based on https://github.com/pborman/uuid, which, in turn, has incorporated back some of the changes Google made. However, allegedly, if you wish to contribute to either of these projects, you need to sign (or have signed) a [Contributor License Agreement](https://cla.developers.google.com/clas). – Gwyneth Llewelyn Jun 26 '20 at 23:11
  • 2
    There is a `NewString`. NewString is equivalent to the expression `uuid.New().String()` – Ertuğrul Altınboğa Feb 18 '22 at 03:27
114

You can generate UUIDs using the go-uuid library. This can be installed with:

go get github.com/nu7hatch/gouuid

You can generate random (version 4) UUIDs with:

import "github.com/nu7hatch/gouuid"

...

u, err := uuid.NewV4()

The returned UUID type is a 16 byte array, so you can retrieve the binary value easily. It also provides the standard hex string representation via its String() method.

The code you have also looks like it will also generate a valid version 4 UUID: the bitwise manipulation you perform at the end set the version and variant fields of the UUID to correctly identify it as version 4. This is done to distinguish random UUIDs from ones generated via other algorithms (e.g. version 1 UUIDs based on your MAC address and time).

James Henstridge
  • 42,244
  • 6
  • 132
  • 114
  • 3
    @Flimzy for people who don't know what they are doing that's most likely true. Introducing unnecessary dependencies is always a bad thing. –  Sep 03 '15 at 16:25
  • @ErikAigner: There are many are valid arguments, and reasond for both. They all boil down to the same reasons to use or not use libraries for anything, and re-hashing them here isn't appropriate. But suggesting that someone is wrong for making one decision over the other is also inappropriate. – Jonathan Hall Sep 03 '15 at 16:43
  • 50 lines of code for every UUID version there is, is hardly a "library"... but whatever. –  Sep 07 '15 at 18:46
  • As far I understand UUID version 1, the time based UUID is not provided by the library, am I missing anything? – Akavall Oct 14 '15 at 20:56
  • 42
    @ErikAigner As long as it is 50 lines I do not have to think about, write and test, I'll take them thank you.. I have other stuff to do then reinvent the wheel. – RickyA Nov 02 '15 at 14:48
  • 4
    This library looks like it is not actually RFC4122 compliant: https://github.com/nu7hatch/gouuid/issues/28 (currently open issue as of 2/1/2016) – Charles L. Feb 01 '16 at 20:21
  • 3
    @ErikAigner reinventing the wheel is also kinda unnecessary. If a library exists and does it well why bother do your own other than if you're doing it to learn how to do it. – Sir Oct 31 '17 at 01:43
  • 1
    @Sir because using 3rd party software is usually 100x more hassle in the long run as to invest 5 minutes implementing it yourself. Rookie mistake. –  Oct 31 '17 at 07:50
  • 9
    @ErikAigner i just find that riduclous. No one reinvents stuff thats done already unless you can do better or need something specific to your program, if you inspect the code and see it does it well why bother do it yourself - not only do you waste development time and cost, you are also potentially going to bring in bugs or simply wrong implementations if you don't know completely what you are doing, these libraries are usually made people who do know what they are doing. It is not rookie to use third party libraries, its only rookie to just assume it works and not inspect the code first.. – Sir Oct 31 '17 at 21:50
78

The go-uuid library is NOT RFC4122 compliant. The variant bits are not set correctly. There have been several attempts by community members to have this fixed but pull requests for the fix are not being accepted.

You can generate UUIDs using the Go uuid library I rewrote based on the go-uuid library. There are several fixes and improvements. This can be installed with:

go get github.com/twinj/uuid

You can generate random (version 4) UUIDs with:

import "github.com/twinj/uuid"

u := uuid.NewV4()

The returned UUID type is an interface and the underlying type is an array.

The library also generates v1 UUIDs and correctly generates v3 and 5 UUIDs. There are several new methods to help with printing and formatting and also new general methods to create UUIDs based off of existing data.

djule5
  • 2,722
  • 2
  • 19
  • 19
twinj
  • 2,009
  • 18
  • 10
  • 4
    I like this package. I've officially adopted it for all my applications. I found that the nu7hatch package wasn't RFC4122-compliant. – Richard Eng Aug 19 '14 at 16:47
  • +1 Agreed, the updates and printing/formatting extensions already included. – eduncan911 Sep 10 '14 at 16:53
  • 4
    Disclaimer missing? :p – chakrit Sep 22 '14 at 07:23
  • 4
    What is the library "below"? You should avoid using above and below on SO as that can change quite quickly. – Stephan Dollberg Jan 18 '15 at 07:10
  • There's also another equivallent, [satori/go.uuid](https://github.com/satori/go.uuid). Didn't try it yet but I am going to use it as a replacement of *nu7hatch* dead project... – shadyyx Apr 07 '16 at 13:06
  • 1
    @shadyyx [satori/go.uuid](https://github.com/satori/go.uuid) seems to be semi-abandoned as of June 2020... the last update was just cosmetic and is from mid-2018. Time to switch... again! – Gwyneth Llewelyn Jun 26 '20 at 23:28
  • 1
    This is now relying on a package the author has seemingly removed from github as of march 2021 – WilliamNHarvey Mar 04 '21 at 19:42
61

"crypto/rand" is cross platform pkg for random bytes generattion

package main

import (
    "crypto/rand"
    "fmt"
)

// Note - NOT RFC4122 compliant
func pseudo_uuid() (uuid string) {

    b := make([]byte, 16)
    _, err := rand.Read(b)
    if err != nil {
        fmt.Println("Error: ", err)
        return
    }

    uuid = fmt.Sprintf("%X-%X-%X-%X-%X", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])

    return
}
Mark
  • 1,035
  • 2
  • 11
  • 24
Ken Cloud
  • 853
  • 7
  • 6
  • 3
    `pseudo_uuid` because it is missing the non-random identifiers like MAC address and whatever else RFC4122 specified? So it's actually *more* random. – Xeoncross Apr 21 '17 at 21:27
  • 2
    good answer; I've expanded it at https://stackoverflow.com/a/48134820/1122270, and I think a lot of folks actually don't need to use UUIDs specifically (nor the sha1/sha256 that I thought I need to use for my own random-id problem), but simply want something random and unique, and your sample provides a good start for a solution – cnst Jan 07 '18 at 06:26
  • Thanks! Simple enough – Karl Pokus Apr 03 '19 at 09:32
  • 1. This doesn't comply to any standard 2. Using just `%x` has issues with byte values less than 128, you need to apply padding, i.e. `%04x` for a byte pair – Ja͢ck May 23 '19 at 08:08
34
u[8] = (u[8] | 0x80) & 0xBF // what's the purpose ?
u[6] = (u[6] | 0x40) & 0x4F // what's the purpose ?

These lines clamp the values of byte 6 and 8 to a specific range. rand.Read returns random bytes in the range 0-255, which are not all valid values for a UUID. As far as I can tell, this should be done for all the values in the slice though.

If you are on linux, you can alternatively call /usr/bin/uuidgen.

package main

import (
    "fmt"
    "log"
    "os/exec"
)

func main() {
    out, err := exec.Command("uuidgen").Output()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s", out)
}

Which yields:

$ go run uuid.go 
dc9076e9-2fda-4019-bd2c-900a8284b9c4
jimt
  • 25,324
  • 8
  • 70
  • 60
  • 27
    Notably, this approach is slow; on a 2012 MacBook Air this strategy can produce only 170 uuids/second. – Jay Taylor Aug 25 '13 at 22:35
  • 12
    And using the nu7hatch/gouuid library, I was able to generate 172,488 uuids/second. – Jay Taylor Aug 25 '13 at 23:09
  • 2
    Good explanation of the `u[6]` and `u[8]` bytes. – chowey May 06 '14 at 17:26
  • If one one is looking for UUID version 1, time based, they could use: `out, err := exec.Command("uuidgen", "-t").Output()` – Akavall Oct 14 '15 at 20:59
  • 3
    On my system (Ubuntu 15.10) I also needed to run the command output through strings.Trim(string(out)) to remove the newline character, otherwise it was inputted up as a trailing ? character in the filesystem. – gregtzar Feb 24 '16 at 01:06
  • 54
    Calling an external program which may or may not exist is an awful way to do this fairly simple task. – Timmmm Apr 04 '16 at 10:06
  • 1
    This should not "be done for all the values in the slice". In a random UUID there are 122 bits of randomness, see the UUID definition or Wikipedia. – Roland Illig Mar 03 '19 at 07:02
  • 1
    The bit manipulation expressions would be clearer if they would first clear the bits and then set them. `u[6] = (u[6] & 0x0F) | 0x40)` says "keep only the lower 4 bits, set the upper 4 bits to 0100". – Roland Illig Mar 03 '19 at 07:06
32

gofrs/uuid is the replacement for satori/go.uuid, which is the most starred UUID package for Go. It supports UUID versions 1-5 and is RFC 4122 and DCE 1.1 compliant.

import "github.com/gofrs/uuid"

// Create a Version 4 UUID, panicking on error
u := uuid.Must(uuid.NewV4())
bmaupin
  • 14,427
  • 5
  • 89
  • 94
12

From Russ Cox's post:

There's no official library. Ignoring error checking, this seems like it would work fine:

f, _ := os.Open("/dev/urandom")
b := make([]byte, 16)
f.Read(b)
f.Close()
uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])

Note: In the original, pre Go 1 version the first line was:

f, _ := os.Open("/dev/urandom", os.O_RDONLY, 0)

Here it compiles and executes, only /dev/urandom returns all zeros in the playground. Should work fine locally.

In the same thread there are some other methods/references/packages found.

zzzz
  • 87,403
  • 16
  • 175
  • 139
  • 15
    This won't generate a valid UUID though: version 4 UUIDs (the type based on random data) require a few bits to be set in a certain way to avoid conflicting with the non-random UUID formats. – James Henstridge Feb 28 '13 at 11:21
  • 4
    Better to use `import "crypto/rand"` in my opinion, but +1 for `uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])`. Combined with the OP's code, and this works great. – chowey May 06 '14 at 17:25
  • 2
    Using the crypto/rand package: http://play.golang.org/p/7JJDx4GL77. zzzz's code does what crypt/rand does, except that it also covers platforms that don't support /dev/urandom (Windows). – Drew Nov 04 '14 at 06:09
  • 1
    It should be noted that this is platform specific – Dan Esparza Oct 27 '16 at 18:03
  • @JamesHenstridge - 99.9999% of the time, no one wants to know what version UUID it is. They just want an ID that's unique. The spec over complates what is a very simple problem. – hookenz Aug 30 '17 at 23:25
  • 2
    @Matt: the problem is that the other UUID formats get their uniqueness by delegating to some other authority (e.g. that your Ethernet MAC address is unique), and then combining that with something else (e.g. the time plus a counter). If you produce a random UUID that isn't correctly formatted as a V4 one, you're weakening the system. – James Henstridge Sep 02 '17 at 09:45
  • Sure. But mac addresses are not always unique. And in virtualized environments are often overridden. That makes it unsuitable where strong guarantees of uniqueness are required. – hookenz Sep 02 '17 at 21:18
  • Downvoted because directly depending on a host-platform in a programming language that's used for multi-platform applications is worse than an external dependency. – Byebye Aug 07 '18 at 08:09
9

Random UUID using package from google:

package main

import (
    "fmt"

    "github.com/google/uuid"
)

func main() {
    out := uuid.Must(uuid.NewRandom()).String()
    fmt.Println(out)
}

Output:

a1c11a53-c4be-488f-89b6-f83bf2d48dab
SillyMaxwell
  • 91
  • 1
  • 2
8

As part of the uuid spec, if you generate a uuid from random it must contain a "4" as the 13th character and a "8", "9", "a", or "b" in the 17th (source).

// this makes sure that the 13th character is "4"
u[6] = (u[6] | 0x40) & 0x4F
// this makes sure that the 17th is "8", "9", "a", or "b"
u[8] = (u[8] | 0x80) & 0xBF 
eric chiang
  • 2,575
  • 2
  • 20
  • 23
7

On Linux, you can read from /proc/sys/kernel/random/uuid:

package main

import "io/ioutil"
import "fmt"

func main() {
    u, _ := ioutil.ReadFile("/proc/sys/kernel/random/uuid")
    fmt.Println(string(u))
}

No external dependencies!

$ go run uuid.go 
3ee995e3-0c96-4e30-ac1e-f7f04fd03e44
soulshake
  • 780
  • 8
  • 12
  • 8
    Downvoted because directly depending on a host-platform in a programming language that's used for multi-platform applications is worse than an external dependency. – Byebye Aug 07 '18 at 08:08
  • 2
    The programming language can be multiplatform, but it's very common solutions Linux specific that never will be on other platform, so, it's a valid response IMO. – ton Oct 08 '19 at 13:58
  • Is this RFC 4122 compliant and what version of UUID is it? – xuiqzy Sep 05 '20 at 18:08
4

The gorand package has a UUID method that returns a Version 4 (randomly generated) UUID in its canonical string representation ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") and it's RFC 4122 compliant.

It also uses the crypto/rand package to ensure the most cryptographically secure generation of UUIDs across all platforms supported by Go.

import "github.com/leonelquinteros/gorand"

func main() {
    uuid, err := gorand.UUID()
    if err != nil {
        panic(err.Error())
    }

    println(uuid)
} 
peiiion
  • 308
  • 2
  • 4
3

So you asked:
Q1. u[8] = (u[8] | 0x80) & 0xBF // what does this do?
Ans: This section defines variant. You can learn more about it from https://datatracker.ietf.org/doc/html/rfc4122#section-4.1.1

Q2. u[6] = (u[6] | 0x40) & 0x4F // what does this do?
Ans: We show version number with the most 4 significant bits so in this case version 4 so we want to set it with "0100". Version 4 is most widely used UUID and its based on random bits generation. It uses 128 bits, Out of which 4 bits are fixed to tell version number and 2 bits are fixed to tell variant. So we have 122 bits left which can be randomly generated.

You can generate UUID v4 by importing package from Google:
https://github.com/google/uuid

package main

import (
    "fmt"
    "github.com/google/uuid"
)

func main() {
    uuid := uuid.New()
    fmt.Println(uuid.String())
}

Also, you can try package I created. It's very light weight and easy to understand. https://github.com/bitactro/UUIDv4

package main

import (
    "fmt"
    "github.com/bitactro/UUIDv4"
)

func main() {
    
    fmt.Println(uuidv4.GenerateUUID4())
}
Ankit Mishra
  • 530
  • 8
  • 16
1

For Windows, I did recently this:

// +build windows

package main

import (
    "syscall"
    "unsafe"
)

var (
    modrpcrt4 = syscall.NewLazyDLL("rpcrt4.dll")
    procUuidCreate = modrpcrt4.NewProc("UuidCreate")
)

const (
    RPC_S_OK = 0
)

func NewUuid() ([]byte, error) {
    var uuid [16]byte
    rc, _, e := syscall.Syscall(procUuidCreate.Addr(), 1,
             uintptr(unsafe.Pointer(&uuid[0])), 0, 0)
    if int(rc) != RPC_S_OK {
        if e != 0 {
            return nil, error(e)
        } else {
            return nil, syscall.EINVAL
        }
    }
    return uuid[:], nil
}
kostix
  • 51,517
  • 14
  • 93
  • 176
  • 4
    Downvoted because directly depending on a host-platform in a programming language that's used for multi-platform applications is worse than an external dependency. – Byebye Aug 07 '18 at 08:10
  • 1
    @Byebye, I wonder why you consider yourself an authority to decide what "is worse" (and what is not) to skim through all the answers given to this question and downvote all which are "system-dependent"? These answers were given to a) widen the horizon of all possible choices, and b) _collectively_ present a _complete picture._ So please stop childishly "playing SO" and put some thought before you action. – kostix Aug 07 '18 at 08:50
  • Short answer. Writing maintainable code. Your answer cannot be ported to a different platform. So if the OP would choose to move their application to another platform the application would break. I've had my fair share of people who wrote platform dependent code where it is totally unnecessary and it creates more trouble then it's worth. You don't write code for just yourself. You write code for the people who will maintain it after you're gone. That's why this answer is not appropriate. No reason to resort to ad hominems and call me childish. – Byebye Aug 07 '18 at 09:12
  • 1
    @Byebye, I overreacted, so please excuse me for the attack. I'm not convinced of your reasons, still, but supposedly it's that "let's agree to disagree" case. – kostix Aug 07 '18 at 09:22
1

This library is our standard for uuid generation and parsing:

https://github.com/pborman/uuid

James McGill
  • 104
  • 3
  • Note that Google's own library (https://github.com/google/uuid) is partially based on https://github.com/pborman/uuid, which, in turn, has incorporated back some of the changes Google made. However, allegedly, if you wish to contribute to _either_ of these projects, you need to sign (or have signed) a [Contributor License Agreement](https://cla.developers.google.com/clas) (CLA). This was apparently not the case in August 2015, when your answer was added; @pborman added that only on [16 Feb 2016](https://github.com/pborman/uuid/commit/c55201b036063326c5b1b89ccfe45a184973d073). – Gwyneth Llewelyn Jun 26 '20 at 23:15
1

The https://github.com/google/uuid module based on RFC 4122 and UUID V4 is currently supported. If you want to use the latest UUID version like UUID v7, This module https://github.com/uuid6/uuid6go-proto could be used.


UUID version 7: An entirely new time-based UUID bit layout sourced from the widely implemented and well known Unix Epoch timestamp source.

unix_ts_ms|ver|rand_a|var|rand_b 

Since the UUID V4 contains random and it is not used for sorting. However, there is a timestamp part on UUID V7, it would be more friendly for sorting.


Sample

    var gen uuid.UUIDv7Generator

    uuid := gen.Next()
    fmt.Println(uuid.ToString())
    fmt.Println(uuid.Time())
    fmt.Println(uuid.Timestamp())

Output

0632933765-357c-31b6-ed56-0daba726b1
2022-09-20 11:28:54 +0800 CST
1663644534
zangw
  • 43,869
  • 19
  • 177
  • 214