github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/util/uuid/generator.go (about)

     1  // Copyright 2019 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  // Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
    12  // Use of this source code is governed by a MIT-style
    13  // license that can be found in licenses/MIT-gofrs.txt.
    14  
    15  // This code originated in github.com/gofrs/uuid.
    16  
    17  package uuid
    18  
    19  import (
    20  	"crypto/md5"
    21  	crypto_rand "crypto/rand"
    22  	"crypto/sha1"
    23  	"encoding/binary"
    24  	"fmt"
    25  	"hash"
    26  	"io"
    27  	"net"
    28  	"sync"
    29  	"time"
    30  
    31  	"github.com/cockroachdb/cockroachdb-parser/pkg/util/syncutil"
    32  	"github.com/cockroachdb/errors"
    33  )
    34  
    35  // Difference in 100-nanosecond intervals between
    36  // UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
    37  const epochStart = 122192928000000000
    38  
    39  type epochFunc func() time.Time
    40  
    41  // HWAddrFunc is the function type used to provide hardware (MAC) addresses.
    42  type HWAddrFunc func() (net.HardwareAddr, error)
    43  
    44  // DefaultGenerator is the default UUID Generator used by this package.
    45  // It uses crypto/rand as the source of entropy.
    46  var DefaultGenerator Generator = NewGen()
    47  
    48  // NewV1 returns a UUID based on the current timestamp and MAC address.
    49  func NewV1() (UUID, error) {
    50  	return DefaultGenerator.NewV1()
    51  }
    52  
    53  // NewV3 returns a UUID based on the MD5 hash of the namespace UUID and name.
    54  func NewV3(ns UUID, name string) UUID {
    55  	return DefaultGenerator.NewV3(ns, name)
    56  }
    57  
    58  // NewV4 returns a randomly generated UUID.
    59  func NewV4() (UUID, error) {
    60  	return DefaultGenerator.NewV4()
    61  }
    62  
    63  // NewV5 returns a UUID based on SHA-1 hash of the namespace UUID and name.
    64  func NewV5(ns UUID, name string) UUID {
    65  	return DefaultGenerator.NewV5(ns, name)
    66  }
    67  
    68  // Generator provides an interface for generating UUIDs.
    69  type Generator interface {
    70  	NewV1() (UUID, error)
    71  	// NewV2(domain byte) (UUID, error) // CRL: Removed support for V2.
    72  	NewV3(ns UUID, name string) UUID
    73  	NewV4() (UUID, error)
    74  	NewV5(ns UUID, name string) UUID
    75  }
    76  
    77  // Gen is a reference UUID generator based on the specifications laid out in
    78  // RFC-4122 and DCE 1.1: Authentication and Security Services. This type
    79  // satisfies the Generator interface as defined in this package.
    80  //
    81  // For consumers who are generating V1 UUIDs, but don't want to expose the MAC
    82  // address of the node generating the UUIDs, the NewGenWithHWAF() function has been
    83  // provided as a convenience. See the function's documentation for more info.
    84  //
    85  // The authors of this package do not feel that the majority of users will need
    86  // to obfuscate their MAC address, and so we recommend using NewGen() to create
    87  // a new generator.
    88  type Gen struct {
    89  	clockSequenceOnce sync.Once
    90  	hardwareAddrOnce  sync.Once
    91  	storageMutex      syncutil.Mutex
    92  
    93  	rand io.Reader
    94  
    95  	epochFunc     epochFunc
    96  	hwAddrFunc    HWAddrFunc
    97  	lastTime      uint64
    98  	clockSequence uint16
    99  	hardwareAddr  [6]byte
   100  }
   101  
   102  // interface check -- build will fail if *Gen doesn't satisfy Generator
   103  var _ Generator = (*Gen)(nil)
   104  
   105  // NewGen returns a new instance of Gen with some default values set. Most
   106  // people should use this.
   107  // NewGen by default uses crypto/rand.Reader as its source of randomness.
   108  func NewGen() *Gen {
   109  	return NewGenWithHWAF(defaultHWAddrFunc)
   110  }
   111  
   112  // NewGenWithReader returns a new instance of gen which uses r as its source of
   113  // randomness.
   114  func NewGenWithReader(r io.Reader) *Gen {
   115  	g := NewGen()
   116  	g.rand = r
   117  	return g
   118  }
   119  
   120  // NewGenWithHWAF builds a new UUID generator with the HWAddrFunc provided. Most
   121  // consumers should use NewGen() instead.
   122  //
   123  // This is used so that consumers can generate their own MAC addresses, for use
   124  // in the generated UUIDs, if there is some concern about exposing the physical
   125  // address of the machine generating the UUID.
   126  //
   127  // The Gen generator will only invoke the HWAddrFunc once, and cache that MAC
   128  // address for all the future UUIDs generated by it. If you'd like to switch the
   129  // MAC address being used, you'll need to create a new generator using this
   130  // function.
   131  func NewGenWithHWAF(hwaf HWAddrFunc) *Gen {
   132  	return &Gen{
   133  		epochFunc:  time.Now,
   134  		hwAddrFunc: hwaf,
   135  		rand:       crypto_rand.Reader,
   136  	}
   137  }
   138  
   139  // NewV1 returns a UUID based on the current timestamp and MAC address.
   140  func (g *Gen) NewV1() (UUID, error) {
   141  	u := UUID{}
   142  
   143  	timeNow, clockSeq, err := g.getClockSequence()
   144  	if err != nil {
   145  		return Nil, err
   146  	}
   147  	binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
   148  	binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
   149  	binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
   150  	binary.BigEndian.PutUint16(u[8:], clockSeq)
   151  
   152  	hardwareAddr, err := g.getHardwareAddr()
   153  	if err != nil {
   154  		return Nil, err
   155  	}
   156  	copy(u[10:], hardwareAddr)
   157  
   158  	u.SetVersion(V1)
   159  	u.SetVariant(VariantRFC4122)
   160  
   161  	return u, nil
   162  }
   163  
   164  // NewV3 returns a UUID based on the MD5 hash of the namespace UUID and name.
   165  func (g *Gen) NewV3(ns UUID, name string) UUID {
   166  	u := newFromHash(md5.New(), ns, name)
   167  	u.SetVersion(V3)
   168  	u.SetVariant(VariantRFC4122)
   169  
   170  	return u
   171  }
   172  
   173  // NewV4 returns a randomly generated UUID.
   174  func (g *Gen) NewV4() (UUID, error) {
   175  	u := UUID{}
   176  	if r, ok := g.rand.(mathRandReader); ok {
   177  		if n, err := r.Read(u[:]); n != len(u) {
   178  			panic("math/rand.Read always returns len(p)")
   179  		} else if err != nil {
   180  			panic("math/rand.Read always returns a nil error")
   181  		}
   182  	} else {
   183  		willEscape := UUID{}
   184  		if _, err := io.ReadFull(g.rand, willEscape[:]); err != nil {
   185  			return Nil, err
   186  		}
   187  		u = willEscape
   188  	}
   189  	u.SetVersion(V4)
   190  	u.SetVariant(VariantRFC4122)
   191  
   192  	return u, nil
   193  }
   194  
   195  // NewV5 returns a UUID based on SHA-1 hash of the namespace UUID and name.
   196  func (g *Gen) NewV5(ns UUID, name string) UUID {
   197  	u := newFromHash(sha1.New(), ns, name)
   198  	u.SetVersion(V5)
   199  	u.SetVariant(VariantRFC4122)
   200  
   201  	return u
   202  }
   203  
   204  // Returns the epoch and clock sequence.
   205  func (g *Gen) getClockSequence() (uint64, uint16, error) {
   206  	var err error
   207  	g.clockSequenceOnce.Do(func() {
   208  		buf := make([]byte, 2)
   209  		if _, err = io.ReadFull(g.rand, buf); err != nil {
   210  			return
   211  		}
   212  		g.clockSequence = binary.BigEndian.Uint16(buf)
   213  	})
   214  	if err != nil {
   215  		return 0, 0, err
   216  	}
   217  
   218  	g.storageMutex.Lock()
   219  	defer g.storageMutex.Unlock()
   220  
   221  	timeNow := g.getEpoch()
   222  	// Clock didn't change since last UUID generation.
   223  	// Should increase clock sequence.
   224  	if timeNow <= g.lastTime {
   225  		g.clockSequence++
   226  	}
   227  	g.lastTime = timeNow
   228  
   229  	return timeNow, g.clockSequence, nil
   230  }
   231  
   232  // Returns the hardware address.
   233  func (g *Gen) getHardwareAddr() ([]byte, error) {
   234  	var err error
   235  	g.hardwareAddrOnce.Do(func() {
   236  		var hwAddr net.HardwareAddr
   237  		if hwAddr, err = g.hwAddrFunc(); err == nil {
   238  			copy(g.hardwareAddr[:], hwAddr)
   239  			return
   240  		}
   241  
   242  		// Initialize hardwareAddr randomly in case
   243  		// of real network interfaces absence.
   244  		if _, err = io.ReadFull(g.rand, g.hardwareAddr[:]); err != nil {
   245  			return
   246  		}
   247  		// Set multicast bit as recommended by RFC-4122
   248  		g.hardwareAddr[0] |= 0x01
   249  	})
   250  	if err != nil {
   251  		return []byte{}, err
   252  	}
   253  	return g.hardwareAddr[:], nil
   254  }
   255  
   256  // Returns the difference between UUID epoch (October 15, 1582)
   257  // and current time in 100-nanosecond intervals.
   258  func (g *Gen) getEpoch() uint64 {
   259  	return epochStart + uint64(g.epochFunc().UnixNano()/100)
   260  }
   261  
   262  // Returns the UUID based on the hashing of the namespace UUID and name.
   263  func newFromHash(h hash.Hash, ns UUID, name string) UUID {
   264  	u := UUID{}
   265  	mustWrite := func(data []byte) {
   266  		if _, err := h.Write(data); err != nil {
   267  			panic(errors.Wrap(err, "failed to write to hash"))
   268  		}
   269  	}
   270  	mustWrite(ns[:])
   271  	mustWrite([]byte(name))
   272  	copy(u[:], h.Sum(nil))
   273  	return u
   274  }
   275  
   276  // Returns the hardware address.
   277  func defaultHWAddrFunc() (net.HardwareAddr, error) {
   278  	ifaces, err := net.Interfaces()
   279  	if err != nil {
   280  		return []byte{}, err
   281  	}
   282  	for _, iface := range ifaces {
   283  		if len(iface.HardwareAddr) >= 6 {
   284  			return iface.HardwareAddr, nil
   285  		}
   286  	}
   287  	return []byte{}, fmt.Errorf("uuid: no HW address found")
   288  }
   289  
   290  // RandomHardwareAddrFunc returns a random hardware address, with the multicast
   291  // and local-admin bits set as per the IEEE802 spec.
   292  func RandomHardwareAddrFunc() (net.HardwareAddr, error) {
   293  	var err error
   294  	var hardwareAddr = make(net.HardwareAddr, 6)
   295  	if _, err = io.ReadFull(crypto_rand.Reader, hardwareAddr[:]); err != nil {
   296  		return []byte{}, err
   297  	}
   298  	// Set multicast bit and local-admin bit to match Postgres.
   299  	hardwareAddr[0] |= 0x03
   300  	return hardwareAddr, nil
   301  }