// Copyright 2026 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package uuid provides support for generating and manipulating UUIDs. // // See [RFC 9562] for details. // // Random components of new UUIDs are generated with a // cryptographically secure random number generator. // // UUIDs may be generated using various algorithms. // The [New] function returns a new UUID generated using // an algorithm suitable for most purposes. // // [RFC 9562]: https://www.rfc-editor.org/rfc/rfc9562.html package uuid import ( "bytes" "cmp" "crypto/rand" "encoding/binary" "encoding/hex" "errors" "sync" "time" ) // A UUID is a Universally Unique Identifier as specified in RFC 9562. // // UUIDs are comparable, such as with the == operator. type UUID [16]byte // Parse returns the UUID represented by s. // // It accepts strings in the following forms: // // f81d4fae-7dec-11d0-a765-00a0c91e6bf6 // {f81d4fae-7dec-11d0-a765-00a0c91e6bf6} // urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6 // f81d4fae7dec11d0a76500a0c91e6bf6 // // Alphabetic characters in the hexadecimal digits may be any case. func Parse(s string) (UUID, error) { var u UUID err := u.UnmarshalText([]byte(s)) return u, err } // MustParse returns the UUID represented by s. // // It panics if s is not a valid string representation of a UUID as defined by [Parse]. func MustParse(s string) UUID { u, err := Parse(s) if err != nil { panic(err) } return u } // New returns a new UUID. // // Programs which do not have a need for a specific UUID generation algorithm should use New. // At this time, New is equivalent to [NewV4]. func New() UUID { return NewV4() } // Nil returns the Nil UUID 00000000-0000-0000-0000-000000000000. // // The Nil UUID is defined in [Section 5.9 of RFC 9562]. // Note that this is not the same as the Go value nil. // // [Section 5.9 of RFC 9562]: https://www.rfc-editor.org/rfc/rfc9562#section-5.9 func Nil() UUID { return UUID{} } // Max returns the Max UUID ffffffff-ffff-ffff-ffff-ffffffffffff. // // The Max UUID is defined in [Section 5.10 of RFC 9562]. // // [Section 5.10 of RFC 9562]: https://www.rfc-editor.org/rfc/rfc9562#section-5.10 func Max() UUID { return UUID{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, } } // String returns the string representation of u. // // It uses the lowercase hex-and-dash representation defined in RFC 9562. func (u UUID) String() string { b, _ := u.MarshalText() return string(b) } // MarshalText implements the [encoding.TextMarshaler] interface. // The encoding is the same as returned by [UUID.String] func (u UUID) MarshalText() ([]byte, error) { return u.AppendText(make([]byte, 0, 36)) } // AppendText implements the [encoding.TextAppender] interface. // The encoding is the same as returned by [UUID.String] func (u UUID) AppendText(b []byte) ([]byte, error) { off := len(b) b = append(b, "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"...) dst := b[off:] hex.Encode(dst[0:8], u[0:4]) hex.Encode(dst[9:13], u[4:6]) hex.Encode(dst[14:18], u[6:8]) hex.Encode(dst[19:23], u[8:10]) hex.Encode(dst[24:36], u[10:16]) return b, nil } var errInvalid = errors.New("invalid uuid") // UnmarshalText implements the [encoding.TextUnmarshaler] interface. // The UUID is expected in a form accepted by [Parse]. func (u *UUID) UnmarshalText(b []byte) error { var dst UUID switch len(b) { case len("urn:uuid:") + 36: // urn:uuid:00000000-0000-0000-0000-000000000000 b = bytes.TrimPrefix(b, []byte("urn:uuid:")) case 2 + 36: // {00000000-0000-0000-0000-000000000000} b = bytes.TrimPrefix(b, []byte("{")) b = bytes.TrimSuffix(b, []byte("}")) case 32: // 00000000000000000000000000000000 if _, err := hex.Decode(dst[:], b); err != nil { return errInvalid } *u = dst return nil } // 00000000-0000-0000-0000-000000000000 if len(b) != 36 { return errInvalid } if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' { return errInvalid } if _, err := hex.Decode(dst[0:4], b[0:8]); err != nil { return errInvalid } if _, err := hex.Decode(dst[4:6], b[9:13]); err != nil { return errInvalid } if _, err := hex.Decode(dst[6:8], b[14:18]); err != nil { return errInvalid } if _, err := hex.Decode(dst[8:10], b[19:23]); err != nil { return errInvalid } if _, err := hex.Decode(dst[10:16], b[24:36]); err != nil { return errInvalid } *u = dst return nil } // Compare compares the UUID u with v. // If u is before v, it returns -1. // If u is after v, it returns +1. // If they are the same, it returns 0. // // Compare uses the big-endian byte order defined in // [Section 6.11 of RFC 9562] for sorting. // // [Section 6.11 of RFC 9562]: https://www.rfc-editor.org/rfc/rfc9562#section-6.11 func (u UUID) Compare(v UUID) int { for i := range u { if c := cmp.Compare(u[i], v[i]); c != 0 { return c } } return 0 } // NewV4 returns a new version 4 UUID. // // Version 4 UUIDs contain 122 bits of random data. func NewV4() UUID { var u UUID rand.Read(u[:]) u.setVersion(4) u.setVariant(0b10) return u } var ( v7mu sync.Mutex v7lastSecs uint64 v7lastTimestamp uint64 ) // NewV7 returns a new version 7 UUID. // // Version 7 UUIDs contain a timestamp in the most significant 48 bits, // and at least 62 bits of random data. // // NewV7 always returns UUIDs which sort in increasing order, // except when the system clock moves backwards. func NewV7() UUID { // UUIDv7 is defined in RFC 9562 section 5.7 as: // // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | unix_ts_ms | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | unix_ts_ms | ver | rand_a | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // |var| rand_b | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | rand_b | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // // We store a 12 bit sub-millisecond timestamp fraction in the rand_a section, // as optionally permitted by the RFC. v7mu.Lock() // Generate our 60-bit timestamp: 48 bits of millisecond-resolution, // followed by 12 bits of 1/4096-millisecond resolution. now := time.Now() secs := uint64(now.Unix()) nanos := uint64(now.Nanosecond()) msecs := nanos / 1000000 frac := nanos - (1000000 * msecs) timestamp := (1000*secs + msecs) << 12 // ms shifted into position timestamp += (frac * 4096) / 1000000 // ns converted to 1/4096-ms units if v7lastSecs > secs { // Time has gone backwards. // This presumably indicates the system clock has changed. // Ignore previously-generated UUIDs. } else if timestamp <= v7lastTimestamp { // This timestamp is the same as a previously-generated UUID. // To preserve the property that we generate UUIDs in order, // use a timestamp 1/4096 millisecond later than the most recently // generated UUID. timestamp = v7lastTimestamp + 1 } v7lastSecs = secs v7lastTimestamp = timestamp v7mu.Unlock() // Insert a gap for the 4 bits of the ver field into the timestamp. hibits := ((timestamp << 4) & 0xffff_ffff_ffff_0000) | (timestamp & 0x0ffff) var u UUID binary.BigEndian.PutUint64(u[0:8], hibits) rand.Read(u[8:]) u.setVersion(7) u.setVariant(0b10) return u } func (u *UUID) setVersion(version byte) { u[6] = (u[6] & 0b0000_1111) | (version << 4) } func (u *UUID) setVariant(variant byte) { u[8] = (u[8] & 0b0011_1111) | (variant << 6) }