From 5d5473c8a5765a569388bac7eb597a3799a7fdbd Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Thu, 23 Nov 2023 19:58:22 +0000 Subject: [PATCH] random: speed up String function for generating larger blocks --- cmd/test/makefiles/makefiles.go | 2 +- lib/random/random.go | 23 +++++++++++++++-------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/cmd/test/makefiles/makefiles.go b/cmd/test/makefiles/makefiles.go index 4b9f8227c..f48778cb0 100644 --- a/cmd/test/makefiles/makefiles.go +++ b/cmd/test/makefiles/makefiles.go @@ -224,7 +224,7 @@ func (r *chargenReader) Read(p []byte) (n int, err error) { func fileName() (name string) { for { length := randSource.Intn(maxFileNameLength-minFileNameLength) + minFileNameLength - name = random.StringFn(length, randSource.Intn) + name = random.StringFn(length, randSource) if _, found := fileNames[name]; !found { break } diff --git a/lib/random/random.go b/lib/random/random.go index 08e752b84..19ed44458 100644 --- a/lib/random/random.go +++ b/lib/random/random.go @@ -4,28 +4,35 @@ package random import ( cryptorand "crypto/rand" "encoding/base64" - "encoding/binary" "fmt" - mathrand "math/rand" + "io" ) // StringFn create a random string for test purposes using the random // number generator function passed in. // // Do not use these for passwords. -func StringFn(n int, randIntn func(n int) int) string { +func StringFn(n int, randReader io.Reader) string { const ( vowel = "aeiou" consonant = "bcdfghjklmnpqrstvwxyz" digit = "0123456789" ) - pattern := []string{consonant, vowel, consonant, vowel, consonant, vowel, consonant, digit} - out := make([]byte, n) - p := 0 + var ( + pattern = []string{consonant, vowel, consonant, vowel, consonant, vowel, consonant, digit} + out = make([]byte, n) + p = 0 + ) + _, err := io.ReadFull(randReader, out) + if err != nil { + panic(fmt.Sprintf("internal error: failed to read from random reader: %v", err)) + } for i := range out { source := pattern[p] p = (p + 1) % len(pattern) - out[i] = source[randIntn(len(source))] + // this generation method means the distribution is slightly biased. However these + // strings are not for passwords so this is deemed OK. + out[i] = source[out[i]%byte(len(source))] } return string(out) } @@ -34,7 +41,7 @@ func StringFn(n int, randIntn func(n int) int) string { // // Do not use these for passwords. func String(n int) string { - return StringFn(n, mathrand.Intn) + return StringFn(n, cryptorand.Reader) } // Password creates a crypto strong password which is just about