Skip to content

Commit

Permalink
Optimize
Browse files Browse the repository at this point in the history
  • Loading branch information
bddjr committed Dec 16, 2024
1 parent f6ea07c commit 5647922
Showing 1 changed file with 47 additions and 50 deletions.
97 changes: 47 additions & 50 deletions rand.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cryptorandstr
import (
"crypto/rand"
"fmt"
"unsafe"
)

const Chars64 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_"
Expand Down Expand Up @@ -31,7 +32,7 @@ func MustRand64(strLen int) string {
return MustRand(strLen, Chars64)
}

// panic when error.
// Panic when error.
func MustRand(strLen int, chars string) string {
s, err := Rand(strLen, chars)
if err != nil {
Expand Down Expand Up @@ -67,27 +68,57 @@ func Rand(strLen int, chars string) (string, error) {
return "", fmt.Errorf("cryptorandstr: chars length %d > 256", len(chars))
}

chunk := make([]byte, 1)
maxB := byte(len(chars) - 1)
r := randWithGC{
outBitLen: bitLen(maxB),
}
difference := 8 - r.outBitLen

out := make([]byte, strLen)
i := 0
for i < strLen {
b, err := r.byte(chunk, difference)
if err != nil {
return "", err
var (
out = make([]byte, strLen)
i int

chunk = make([]byte, 1)
n int
err error

cache uint16
cacheBitLen byte

maxB = byte(len(chars) - 1)
outBitLen = bitLen(maxB)
difference = 8 - outBitLen
b byte
)

for {
if cacheBitLen >= outBitLen {
// read cache
b = byte(cache)
cache >>= outBitLen
cacheBitLen -= outBitLen
} else {
// random
for {
n, err = rand.Reader.Read(chunk)
if err != nil {
return "", err
}
if n == 1 {
break
}
}
b = chunk[0]
// write cache
cache <<= difference
cache |= uint16(b >> outBitLen)
cacheBitLen += difference
}

b <<= difference
b >>= difference
if b <= maxB {
out[i] = chars[b]
i++
if i == strLen {
return *(*string)(unsafe.Pointer(&out)), nil
}
}
}

return string(out), nil
}

func bitLen(b byte) (l byte) {
Expand All @@ -97,37 +128,3 @@ func bitLen(b byte) (l byte) {
}
return
}

type randWithGC struct {
outBitLen byte
cacheBitLen byte
cache uint16
}

func (r *randWithGC) byte(chunk []byte, difference byte) (byte, error) {
// read cache
if r.cacheBitLen >= r.outBitLen {
b := (byte(r.cache) << difference) >> difference
r.cache >>= r.outBitLen
r.cacheBitLen -= r.outBitLen
return b, nil
}

// random
for {
n, err := rand.Reader.Read(chunk)
if err != nil {
return 0, err
}
if n == 1 {
break
}
}

// write cache
r.cache <<= difference
r.cache |= uint16(chunk[0] >> r.outBitLen)
r.cacheBitLen += difference

return (chunk[0] << difference) >> difference, nil
}

0 comments on commit 5647922

Please sign in to comment.