github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/twinj/uuid/rfc4122.go (about)

     1  package uuid
     2  
     3  /***************
     4   * Date: 14/02/14
     5   * Time: 7:44 PM
     6   ***************/
     7  
     8  import (
     9  	"crypto/md5"
    10  	"crypto/rand"
    11  	"crypto/sha1"
    12  	"encoding/binary"
    13  	"log"
    14  	seed "math/rand"
    15  	"net"
    16  )
    17  
    18  const (
    19  	length = 16
    20  
    21  	// 3F used by RFC4122 although 1F works for all
    22  	variantSet = 0x3F
    23  
    24  	// rather than using 0xC0 we use 0xE0 to retrieve the variant
    25  	// The result is the same for all other variants
    26  	// 0x80 and 0xA0 are used to identify RFC4122 compliance
    27  	variantGet = 0xE0
    28  )
    29  
    30  var (
    31  	// nodeID is the default Namespace node
    32  	nodeId = []byte{
    33  		// 00.192.79.212.48.200
    34  		0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
    35  	}
    36  	// The following standard UUIDs are for use with V3 or V5 UUIDs.
    37  	NamespaceDNS  = &Struct{0x6ba7b810, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length}
    38  	NamespaceURL  = &Struct{0x6ba7b811, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length}
    39  	NamespaceOID  = &Struct{0x6ba7b812, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length}
    40  	NamespaceX500 = &Struct{0x6ba7b814, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length}
    41  
    42  	state State
    43  )
    44  
    45  func init() {
    46  	seed.Seed((int64(timestamp())^int64(gregorianToUNIXOffset))*0x6ba7b814<<0x6ba7b812 | 1391463463)
    47  	state = State{
    48  		randomNode:     true,
    49  		randomSequence: true,
    50  		past:           Timestamp((1391463463 * 10000000) + (100 * 10) + gregorianToUNIXOffset),
    51  		node:           nodeId,
    52  		sequence:       uint16(seed.Int()) & 0x3FFF,
    53  		saver:          nil,
    54  	}
    55  }
    56  
    57  // NewV1 will generate a new RFC4122 version 1 UUID
    58  func NewV1() UUID {
    59  	state.Lock()
    60  	defer state.Unlock()
    61  	now := currentUUIDTimestamp()
    62  	state.read(now, currentUUIDNodeId())
    63  	state.persist()
    64  	return formatV1(now, uint16(1), ReservedRFC4122, state.node)
    65  }
    66  
    67  // NewV3 will generate a new RFC4122 version 3 UUID
    68  // V3 is based on the MD5 hash of a namespace identifier UUID and
    69  // any type which implements the UniqueName interface for the name.
    70  // For strings and slices cast to a Name type
    71  func NewV3(pNs UUID, pName UniqueName) UUID {
    72  	o := new(Array)
    73  	// Set all bits to MD5 hash generated from namespace and name.
    74  	Digest(o, pNs, pName, md5.New())
    75  	o.setRFC4122Variant()
    76  	o.setVersion(3)
    77  	return o
    78  }
    79  
    80  // NewV4 will generate a new RFC4122 version 4 UUID
    81  // A cryptographically secure random UUID.
    82  func NewV4() UUID {
    83  	o := new(Array)
    84  	// Read random values (or pseudo-randomly) into Array type.
    85  	_, err := rand.Read(o[:length])
    86  	if err != nil {
    87  		panic(err)
    88  	}
    89  	o.setRFC4122Variant()
    90  	o.setVersion(4)
    91  	return o
    92  }
    93  
    94  // NewV5 will generate a new RFC4122 version 5 UUID
    95  // Generate a UUID based on the SHA-1 hash of a namespace
    96  // identifier and a name.
    97  func NewV5(pNs UUID, pName UniqueName) UUID {
    98  	o := new(Array)
    99  	Digest(o, pNs, pName, sha1.New())
   100  	o.setRFC4122Variant()
   101  	o.setVersion(5)
   102  	return o
   103  }
   104  
   105  // either generates a random node when there is an error or gets
   106  // the pre initialised one
   107  func currentUUIDNodeId() (node net.HardwareAddr) {
   108  	if state.randomNode {
   109  		b := make([]byte, 16+6)
   110  		_, err := rand.Read(b)
   111  		if err != nil {
   112  			log.Println("UUID.currentUUIDNodeId error:", err)
   113  			node = nodeId
   114  			return
   115  		}
   116  		h := sha1.New()
   117  		h.Write(b)
   118  		binary.Write(h, binary.LittleEndian, state.sequence)
   119  		node = h.Sum(nil)[:6]
   120  		if err != nil {
   121  			log.Println("UUID.currentUUIDNodeId error:", err)
   122  			node = nodeId
   123  			return
   124  		}
   125  		// Mark as randomly generated
   126  		node[0] |= 0x01
   127  	} else {
   128  		node = state.node
   129  	}
   130  	return
   131  }
   132  
   133  // Unmarshal data into struct for V1 UUIDs
   134  func formatV1(pNow Timestamp, pVersion uint16, pVariant byte, pNode []byte) UUID {
   135  	o := new(Struct)
   136  	o.timeLow = uint32(pNow & 0xFFFFFFFF)
   137  	o.timeMid = uint16((pNow >> 32) & 0xFFFF)
   138  	o.timeHiAndVersion = uint16((pNow >> 48) & 0x0FFF)
   139  	o.timeHiAndVersion |= uint16(pVersion << 12)
   140  	o.sequenceLow = byte(state.sequence & 0xFF)
   141  	o.sequenceHiAndVariant = byte((state.sequence & 0x3F00) >> 8)
   142  	o.sequenceHiAndVariant |= pVariant
   143  	o.node = pNode
   144  	o.size = length
   145  	return o
   146  }