pkg: remove random package

The unnecessary `random` package has been removed in favor of using the
`math/rand` package directly. Seeding of the random value from crypto
has been added to the `stringid` package to account for the change.

May need to add an equivalent seed to `namesgenerator`, but this is
often used with `stringid` and has collision protection.

Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
Stephen J Day 2017-05-08 17:02:02 -07:00
parent 4b846a125b
commit 66cfe61f71
No known key found for this signature in database
GPG Key ID: 67B3DED84EDC823F
5 changed files with 32 additions and 111 deletions

View File

@ -2,8 +2,7 @@ package namesgenerator
import (
"fmt"
"github.com/docker/docker/pkg/random"
"math/rand"
)
var (
@ -594,15 +593,14 @@ var (
// formatted as "adjective_surname". For example 'focused_turing'. If retry is non-zero, a random
// integer between 0 and 10 will be added to the end of the name, e.g `focused_turing3`
func GetRandomName(retry int) string {
rnd := random.Rand
begin:
name := fmt.Sprintf("%s_%s", left[rnd.Intn(len(left))], right[rnd.Intn(len(right))])
name := fmt.Sprintf("%s_%s", left[rand.Intn(len(left))], right[rand.Intn(len(right))])
if name == "boring_wozniak" /* Steve Wozniak is not boring */ {
goto begin
}
if retry > 0 {
name = fmt.Sprintf("%s%d", name, rnd.Intn(10))
name = fmt.Sprintf("%s%d", name, rand.Intn(10))
}
return name
}

View File

@ -1,71 +0,0 @@
package random
import (
cryptorand "crypto/rand"
"io"
"math"
"math/big"
"math/rand"
"sync"
"time"
)
// Rand is a global *rand.Rand instance, which initialized with NewSource() source.
var Rand = rand.New(NewSource())
// Reader is a global, shared instance of a pseudorandom bytes generator.
// It doesn't consume entropy.
var Reader io.Reader = &reader{rnd: Rand}
// copypaste from standard math/rand
type lockedSource struct {
lk sync.Mutex
src rand.Source
}
func (r *lockedSource) Int63() (n int64) {
r.lk.Lock()
n = r.src.Int63()
r.lk.Unlock()
return
}
func (r *lockedSource) Seed(seed int64) {
r.lk.Lock()
r.src.Seed(seed)
r.lk.Unlock()
}
// NewSource returns math/rand.Source safe for concurrent use and initialized
// with current unix-nano timestamp
func NewSource() rand.Source {
var seed int64
if cryptoseed, err := cryptorand.Int(cryptorand.Reader, big.NewInt(math.MaxInt64)); err != nil {
// This should not happen, but worst-case fallback to time-based seed.
seed = time.Now().UnixNano()
} else {
seed = cryptoseed.Int64()
}
return &lockedSource{
src: rand.NewSource(seed),
}
}
type reader struct {
rnd *rand.Rand
}
func (r *reader) Read(b []byte) (int, error) {
i := 0
for {
val := r.rnd.Int63()
for val > 0 {
b[i] = byte(val)
i++
if i == len(b) {
return i, nil
}
val >>= 8
}
}
}

View File

@ -1,22 +0,0 @@
package random
import (
"math/rand"
"sync"
"testing"
)
// for go test -v -race
func TestConcurrency(t *testing.T) {
rnd := rand.New(NewSource())
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
rnd.Int63()
wg.Done()
}()
}
wg.Wait()
}

View File

@ -2,15 +2,17 @@
package stringid
import (
"crypto/rand"
cryptorand "crypto/rand"
"encoding/hex"
"fmt"
"io"
"math"
"math/big"
"math/rand"
"regexp"
"strconv"
"strings"
"github.com/docker/docker/pkg/random"
"time"
)
const shortLen = 12
@ -39,12 +41,8 @@ func TruncateID(id string) string {
return id
}
func generateID(crypto bool) string {
func generateID(r io.Reader) string {
b := make([]byte, 32)
r := random.Reader
if crypto {
r = rand.Reader
}
for {
if _, err := io.ReadFull(r, b); err != nil {
panic(err) // This shouldn't happen
@ -62,14 +60,14 @@ func generateID(crypto bool) string {
// GenerateRandomID returns a unique id.
func GenerateRandomID() string {
return generateID(true)
return generateID(cryptorand.Reader)
}
// GenerateNonCryptoID generates unique id without using cryptographically
// secure sources of random.
// It helps you to save entropy.
func GenerateNonCryptoID() string {
return generateID(false)
return generateID(readerFunc(rand.Read))
}
// ValidateID checks whether an ID string is a valid image ID.
@ -79,3 +77,23 @@ func ValidateID(id string) error {
}
return nil
}
func init() {
// safely set the seed globally so we generate random ids. Tries to use a
// crypto seed before falling back to time.
var seed int64
if cryptoseed, err := cryptorand.Int(cryptorand.Reader, big.NewInt(math.MaxInt64)); err != nil {
// This should not happen, but worst-case fallback to time-based seed.
seed = time.Now().UnixNano()
} else {
seed = cryptoseed.Int64()
}
rand.Seed(seed)
}
type readerFunc func(p []byte) (int, error)
func (fn readerFunc) Read(p []byte) (int, error) {
return fn(p)
}

View File

@ -5,8 +5,6 @@ import (
"bytes"
"math/rand"
"strings"
"github.com/docker/docker/pkg/random"
)
// GenerateRandomAlphaOnlyString generates an alphabetical random string with length n.
@ -15,7 +13,7 @@ func GenerateRandomAlphaOnlyString(n int) string {
letters := []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
b := make([]byte, n)
for i := range b {
b[i] = letters[random.Rand.Intn(len(letters))]
b[i] = letters[rand.Intn(len(letters))]
}
return string(b)
}