New Upstream Release - golang-github-dchest-uniuri
Ready changes
Summary
Merged new upstream version: 0.0~git20221007.a87ec9d+ds (was: 0.0~git20200228.7aecb25).
Resulting package
Built on 2022-12-14T17:27 (took 3m1s)
The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:
apt install -t fresh-releases golang-github-dchest-uniuri-dev
Lintian Result
- golang-github-dchest-uniuri-dev_0.0~git20221007.a87ec9d+ds-1~jan+nur1_all.deb
- golang-github-dchest-uniuri_0.0~git20221007.a87ec9d+ds-1~jan+nur1.dsc
- golang-github-dchest-uniuri_0.0~git20221007.a87ec9d+ds-1~jan+nur1_amd64.buildinfo
- golang-github-dchest-uniuri_0.0~git20221007.a87ec9d+ds-1~jan+nur1_amd64.changes
Diff
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 245a2f5..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-language: go
-
-go:
- - 1.3
- - 1.4
- - tip
diff --git a/README.md b/README.md
index b321a5f..6240bc9 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,6 @@
Package uniuri
=====================
-[![Build Status](https://travis-ci.org/dchest/uniuri.svg)](https://travis-ci.org/dchest/uniuri)
-
```go
import "github.com/dchest/uniuri"
```
diff --git a/debian/changelog b/debian/changelog
index 4e599ca..d02abaa 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+golang-github-dchest-uniuri (0.0~git20221007.a87ec9d+ds-1) UNRELEASED; urgency=low
+
+ * New upstream snapshot.
+
+ -- Debian Janitor <janitor@jelmer.uk> Wed, 14 Dec 2022 17:24:26 -0000
+
golang-github-dchest-uniuri (0.0~git20200228.7aecb25-1) unstable; urgency=medium
* New upstream release
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..f5854e7
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module github.com/dchest/uniuri
+
+go 1.19
diff --git a/uniuri.go b/uniuri.go
index 6393446..dd96592 100644
--- a/uniuri.go
+++ b/uniuri.go
@@ -22,7 +22,10 @@
// read from it.
package uniuri
-import "crypto/rand"
+import (
+ "crypto/rand"
+ "math"
+)
const (
// StdLen is a standard length of uniuri string to achive ~95 bits of entropy.
@@ -47,35 +50,71 @@ func NewLen(length int) string {
return NewLenChars(length, StdChars)
}
-// NewLenChars returns a new random string of the provided length, consisting
+// maxBufLen is the maximum length of a temporary buffer for random bytes.
+const maxBufLen = 2048
+
+// minRegenBufLen is the minimum length of temporary buffer for random bytes
+// to fill after the first rand.Read request didn't produce the full result.
+// If the initial buffer is smaller, this value is ignored.
+// Rationale: for performance, assume it's pointless to request fewer bytes from rand.Read.
+const minRegenBufLen = 16
+
+// estimatedBufLen returns the estimated number of random bytes to request
+// given that byte values greater than maxByte will be rejected.
+func estimatedBufLen(need, maxByte int) int {
+ return int(math.Ceil(float64(need) * (255 / float64(maxByte))))
+}
+
+// NewLenCharsBytes returns a new random byte slice of the provided length, consisting
// of the provided byte slice of allowed characters (maximum 256).
-func NewLenChars(length int, chars []byte) string {
+func NewLenCharsBytes(length int, chars []byte) []byte {
if length == 0 {
- return ""
+ return nil
}
clen := len(chars)
if clen < 2 || clen > 256 {
panic("uniuri: wrong charset length for NewLenChars")
}
maxrb := 255 - (256 % clen)
- b := make([]byte, length)
- r := make([]byte, length+(length/4)) // storage for random bytes.
+ buflen := estimatedBufLen(length, maxrb)
+ if buflen < length {
+ buflen = length
+ }
+ if buflen > maxBufLen {
+ buflen = maxBufLen
+ }
+ buf := make([]byte, buflen) // storage for random bytes
+ out := make([]byte, length) // storage for result
i := 0
for {
- if _, err := rand.Read(r); err != nil {
+ if _, err := rand.Read(buf[:buflen]); err != nil {
panic("uniuri: error reading random bytes: " + err.Error())
}
- for _, rb := range r {
+ for _, rb := range buf[:buflen] {
c := int(rb)
if c > maxrb {
// Skip this number to avoid modulo bias.
continue
}
- b[i] = chars[c%clen]
+ out[i] = chars[c%clen]
i++
if i == length {
- return string(b)
+ return out
}
}
+ // Adjust new requested length, but no smaller than minRegenBufLen.
+ buflen = estimatedBufLen(length-i, maxrb)
+ if buflen < minRegenBufLen && minRegenBufLen < cap(buf) {
+ buflen = minRegenBufLen
+ }
+ if buflen > maxBufLen {
+ buflen = maxBufLen
+ }
}
}
+
+// NewLenChars returns a new random string of the provided length, consisting
+// of the provided byte slice of allowed characters (maximum 256).
+func NewLenChars(length int, chars []byte) string {
+ return string(NewLenCharsBytes(length, chars))
+}
diff --git a/uniuri_test.go b/uniuri_test.go
index 0e26efe..dd3c365 100644
--- a/uniuri_test.go
+++ b/uniuri_test.go
@@ -7,7 +7,24 @@
package uniuri
-import "testing"
+import (
+ "bytes"
+ "testing"
+)
+
+func validateBytes(t *testing.T, u []byte, chars []byte) {
+ for _, c := range u {
+ var present bool
+ for _, a := range chars {
+ if a == c {
+ present = true
+ }
+ }
+ if !present {
+ t.Fatalf("chars not allowed in %q", u)
+ }
+ }
+}
func validateChars(t *testing.T, u string, chars []byte) {
for _, c := range u {
@@ -55,6 +72,25 @@ func TestNewLen(t *testing.T) {
}
}
+func TestNewLenCharsBytes(t *testing.T) {
+ length := 10
+ chars := []byte("01234567")
+ u := NewLenCharsBytes(length, chars)
+
+ // Check length
+ if len(u) != length {
+ t.Fatalf("wrong length: expected %d, got %d", StdLen, len(u))
+ }
+ // Check that only allowed characters are present
+ validateBytes(t, u, chars)
+
+ // Check that two generated strings are different
+ u2 := NewLenCharsBytes(length, chars)
+ if bytes.Equal(u, u2) {
+ t.Fatalf("not unique: %q and %q", u, u2)
+ }
+}
+
func TestNewLenChars(t *testing.T) {
length := 10
chars := []byte("01234567")
@@ -96,7 +132,61 @@ func TestBias(t *testing.T) {
for k, n := range counts {
diff := float64(n) / avg
if diff < 0.95 || diff > 1.05 {
- t.Errorf("Bias on '%c': expected average %f, got %d", k, avg, n)
+ t.Errorf("Possible bias on '%c': expected average %f, got %d", k, avg, n)
}
}
}
+
+var (
+ sixtyFourChars = append(StdChars, []byte{'+', '/'}...)
+ sixtyFiveChars = append(sixtyFourChars, []byte{'.'}...)
+ threeChars = []byte{'a', 'b', 'c'}
+)
+
+func BenchmarkLen16Chars65(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _ = NewLenChars(StdLen, sixtyFiveChars)
+ }
+}
+
+func BenchmarkLen16Chars64(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _ = NewLenChars(StdLen, sixtyFourChars)
+ }
+}
+
+func BenchmarkLen16Chars62(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _ = NewLenChars(StdLen, StdChars)
+ }
+}
+
+func BenchmarkLen16Chars3(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _ = NewLenChars(StdLen, threeChars)
+ }
+}
+
+func BenchmarkLen1024Chars65(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _ = NewLenChars(1024, sixtyFiveChars)
+ }
+}
+
+func BenchmarkLen1024Chars64(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _ = NewLenChars(1024, sixtyFourChars)
+ }
+}
+
+func BenchmarkLen1024Chars62(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _ = NewLenChars(1024, StdChars)
+ }
+}
+
+func BenchmarkLen1024Chars3(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _ = NewLenChars(1024, threeChars)
+ }
+}
Debdiff
[The following lists of changes regard files as different if they have different names, permissions or owners.]
Files in second set of .debs but not in first
-rw-r--r-- root/root /usr/share/gocode/src/github.com/dchest/uniuri/go.mod
No differences were encountered in the control files