zuid

package
v0.0.0-alpha.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 7, 2025 License: Apache-2.0 Imports: 7 Imported by: 6

Documentation

Overview

package zid provides some unique ID sources.

Throughout this package,

Random value sources are (cited from rand.Reader):

  • On Linux, FreeBSD, Dragonfly, and Solaris, Reader uses getrandom(2).
  • On legacy Linux (< 3.17), Reader opens /dev/urandom on first use.
  • On macOS, iOS, and OpenBSD Reader, uses arc4random_buf(3).
  • On NetBSD, Reader uses the kern.arandom sysctl.
  • On Windows, Reader uses the ProcessPrng API.
  • On js/wasm, Reader uses the Web Crypto API.
  • On wasip1/wasm, Reader uses random_get.

References:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func ContextWithID

func ContextWithID(ctx context.Context, key, id string) context.Context

ContextWithID save an unique ID in the context with given key. A new context created with context.Background is used when nil context was given. Note that calling ContextWithID multiple times overwrites the existing unique ID. Use FromContext to extract stored id from the context.

Example
package main

import (
	"context"
	"fmt"

	"github.com/aileron-projects/go/zx/zuid"
)

func main() {
	ctx := zuid.ContextWithID(context.Background(), "key", "example-unique-id")
	uid := zuid.FromContext(ctx, "key")
	fmt.Println(uid)
}
Output:

example-unique-id

func FromContext

func FromContext(ctx context.Context, key string) string

FromContext returns an unique ID extracted from the context. Empty string will be returned if no unique ID found in the context or the context is nil. Use ContextWithID to save an id to the context.

func NewCount

func NewCount() []byte

NewCount returns a new 30 bytes counter based ID. The returned ID is sortable by time, nearly has the same entropy as UUIDv4 and is hard to guess because of the random value. IDs are hard to duplicate but the possibility is not zero. The returned 30 bytes IDs do not contain any padding string when encoded with encoding/hex, encoding/base64 and encoding/base32.

ID consists of:

  • 8 bytes unix time in microsecond. Valid until January 10th, 294247.
  • 14 bytes random value read from crypto/rand.Reader.
  • 8 bytes unsigned integer counter (reset to zero when overflow).

Bit arrangements:

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         timestamp_high                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         timestamp_low                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             random                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             random                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             random                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            random             |         counter_high          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        counter_middle                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          counter_low          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Encoded ID examples: (time:2000-01-01, random:12345678901234 counter:1)

Example
package main

import (
	"encoding/base32"
	"encoding/base64"
	"encoding/hex"
	"fmt"

	"github.com/aileron-projects/go/zx/zuid"
)

func main() {
	id := zuid.NewCount()
	fmt.Println("Len :", len(id))
	fmt.Println("hex        :", hex.EncodeToString(id))
	fmt.Println("base32.Std :", base32.StdEncoding.EncodeToString(id))
	fmt.Println("base32.Hex :", base32.HexEncoding.EncodeToString(id))
	fmt.Println("base64.Std :", base64.StdEncoding.EncodeToString(id))
	fmt.Println("base64.URL :", base64.URLEncoding.EncodeToString(id))
}

func NewHost

func NewHost() []byte

NewHost returns a new 30 bytes hostname based ID. The returned ID is sortable by time, nearly has the same entropy as UUIDv4 and is hard to guess because of the random value. IDs are hard to duplicate but the possibility is not zero. The returned 30 bytes IDs do not contain any padding string when encoded with encoding/hex, encoding/base64 and encoding/base32.

ID consists of:

  • 8 bytes unix time in microsecond. Valid until January 10th, 294247.
  • 8 bytes FNV1a/64 hash of the hostname.
  • 14 bytes random value read from crypto/rand.Reader.

Bit arrangements:

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         timestamp_high                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         timestamp_low                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    FNV1a/64(hostname)_high                    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    FNV1a/64(hostname)_low                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             random                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             random                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             random                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|             random            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Encoded ID examples: (time:2000-01-01, random:12345678901234 hostFNV:host1234)

Encoding the returned ID will results in the following pattern:

  • Base16 : ^[0-9a-fA-F]{60}$
  • Base32 : ^[2-7A-Z]{48}$
  • Base32Hex : ^[0-9A-V]{48}$
  • Base64 : ^[0-9a-zA-Z+/]{40}$
  • Base64Raw : ^[0-9a-zA-Z+/]{40}$
  • Base64URL : ^[0-9a-zA-Z-_]{40}$
  • Base64RawURL : ^[0-9a-zA-Z-_]{40}$
Example
package main

import (
	"encoding/base32"
	"encoding/base64"
	"encoding/hex"
	"fmt"

	"github.com/aileron-projects/go/zx/zuid"
)

func main() {
	id := zuid.NewHost()
	fmt.Println("Len :", len(id))
	fmt.Println("hex        :", hex.EncodeToString(id))
	fmt.Println("base32.Std :", base32.StdEncoding.EncodeToString(id))
	fmt.Println("base32.Hex :", base32.HexEncoding.EncodeToString(id))
	fmt.Println("base64.Std :", base64.StdEncoding.EncodeToString(id))
	fmt.Println("base64.URL :", base64.URLEncoding.EncodeToString(id))
}

func NewTime

func NewTime() []byte

NewTime returns a new 30 bytes timestamp based ID. The returned ID is sortable by time, higher entropy than UUIDv4 and is hard to guess because of the random value. IDs are hard to duplicate but the possibility is not zero. The returned 30 bytes IDs do not contain any padding string when encoded with encoding/hex, encoding/base64 and encoding/base32.

ID consists of:

  • 8 bytes unix time in microsecond. Valid until January 10th, 294247.
  • 22 bytes random value read from crypto/rand.Reader.

Bit arrangements:

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         timestamp_high                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         timestamp_low                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             random                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             random                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             random                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             random                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             random                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|             random            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Encoded ID examples: (time:2000-01-01, random:1234567890123456789012)

Encoding the returned ID will results in the following pattern:

  • Base16 : ^[0-9a-fA-F]{60}$
  • Base32 : ^[2-7A-Z]{48}$
  • Base32Hex : ^[0-9A-V]{48}$
  • Base64 : ^[0-9a-zA-Z+/]{40}$
  • Base64Raw : ^[0-9a-zA-Z+/]{40}$
  • Base64URL : ^[0-9a-zA-Z-_]{40}$
  • Base64RawURL : ^[0-9a-zA-Z-_]{40}$
Example
package main

import (
	"encoding/base32"
	"encoding/base64"
	"encoding/hex"
	"fmt"

	"github.com/aileron-projects/go/zx/zuid"
)

func main() {
	id := zuid.NewTime()
	fmt.Println("Len :", len(id))
	fmt.Println("hex        :", hex.EncodeToString(id))
	fmt.Println("base32.Std :", base32.StdEncoding.EncodeToString(id))
	fmt.Println("base32.Hex :", base32.HexEncoding.EncodeToString(id))
	fmt.Println("base64.Std :", base64.StdEncoding.EncodeToString(id))
	fmt.Println("base64.URL :", base64.URLEncoding.EncodeToString(id))
}

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL