gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

rand.go (1683B)


      1 // Copyright 2018 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // Package detrand provides deterministically random functionality.
      6 //
      7 // The pseudo-randomness of these functions is seeded by the program binary
      8 // itself and guarantees that the output does not change within a program,
      9 // while ensuring that the output is unstable across different builds.
     10 package detrand
     11 
     12 import (
     13 	"encoding/binary"
     14 	"hash/fnv"
     15 	"os"
     16 )
     17 
     18 // Disable disables detrand such that all functions returns the zero value.
     19 // This function is not concurrent-safe and must be called during program init.
     20 func Disable() {
     21 	randSeed = 0
     22 }
     23 
     24 // Bool returns a deterministically random boolean.
     25 func Bool() bool {
     26 	return randSeed%2 == 1
     27 }
     28 
     29 // Intn returns a deterministically random integer between 0 and n-1, inclusive.
     30 func Intn(n int) int {
     31 	if n <= 0 {
     32 		panic("must be positive")
     33 	}
     34 	return int(randSeed % uint64(n))
     35 }
     36 
     37 // randSeed is a best-effort at an approximate hash of the Go binary.
     38 var randSeed = binaryHash()
     39 
     40 func binaryHash() uint64 {
     41 	// Open the Go binary.
     42 	s, err := os.Executable()
     43 	if err != nil {
     44 		return 0
     45 	}
     46 	f, err := os.Open(s)
     47 	if err != nil {
     48 		return 0
     49 	}
     50 	defer f.Close()
     51 
     52 	// Hash the size and several samples of the Go binary.
     53 	const numSamples = 8
     54 	var buf [64]byte
     55 	h := fnv.New64()
     56 	fi, err := f.Stat()
     57 	if err != nil {
     58 		return 0
     59 	}
     60 	binary.LittleEndian.PutUint64(buf[:8], uint64(fi.Size()))
     61 	h.Write(buf[:8])
     62 	for i := int64(0); i < numSamples; i++ {
     63 		if _, err := f.ReadAt(buf[:], i*fi.Size()/numSamples); err != nil {
     64 			return 0
     65 		}
     66 		h.Write(buf[:])
     67 	}
     68 	return h.Sum64()
     69 }