...

Source file src/google.golang.org/protobuf/internal/detrand/rand.go

Documentation: google.golang.org/protobuf/internal/detrand

     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  }
    70  

View as plain text