Skip to content

Commit

Permalink
Merge pull request #1 from jedib0t/optimization
Browse files Browse the repository at this point in the history
passphrase: ahead of time capitalization
  • Loading branch information
jedib0t authored Apr 20, 2024
2 parents c0235a2 + db41472 commit 686e61a
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 16 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ goos: linux
goarch: amd64
pkg: github.com/jedib0t/go-passwords/passphrase
cpu: AMD Ryzen 9 5900X 12-Core Processor
BenchmarkGenerator_Generate-12 3015926 392.7 ns/op 167 B/op 8 allocs/op
BenchmarkGenerator_Generate-12 4030634 292.0 ns/op 144 B/op 5 allocs/op
PASS
ok github.com/jedib0t/go-passwords/passphrase 1.603s
Expand Down
3 changes: 2 additions & 1 deletion passphrase/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

var (
ErrDictionaryTooSmall = errors.New(fmt.Sprintf("dictionary cannot have less than %d words after word-length restrictions are applied", MinWordsInDictionary))
ErrNumWordsInvalid = errors.New(fmt.Sprintf("number of words cannot be less than %d", MinNumWords))
ErrNumWordsTooSmall = errors.New(fmt.Sprintf("number of words cannot be less than %d", NumWordsMin))
ErrNumWordsTooLarge = errors.New(fmt.Sprintf("number of words cannot be more than %d", NumWordsMax))
ErrWordLengthInvalid = errors.New("word-length rule invalid")
)
35 changes: 21 additions & 14 deletions passphrase/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import (
)

const (
MinNumWords = 2
MinWordsInDictionary = 256
NumWordsMin = 2
NumWordsMax = 32
)

type Generator interface {
Expand Down Expand Up @@ -48,23 +49,14 @@ func NewGenerator(rules ...Rule) (Generator, error) {
func (g *generator) Generate() string {
var words []string

// generate words
// select words
for idx := 0; idx < g.numWords; idx++ {
var word string
for word == "" || slices.Contains(words, word) {
word = g.dictionary[g.rng.IntN(len(g.dictionary))]
}
words = append(words, word)
}
// capitalize all words
if g.capitalize {
for idx := range words {
r, size := utf8.DecodeRuneInString(words[idx])
if r != utf8.RuneError {
words[idx] = string(unicode.ToUpper(r)) + words[idx][size:]
}
}
}
// inject a random number after one of the words
if g.withNumber {
idx := g.rng.IntN(len(words))
Expand All @@ -83,15 +75,30 @@ func (g *generator) sanitize() (Generator, error) {
if g.wordLenMin < 1 || g.wordLenMin > g.wordLenMax {
return nil, ErrWordLengthInvalid
}
// filter the dictionary and remove too-short or too-long words

// remove words that are too-short & too-long
slices.DeleteFunc(g.dictionary, func(word string) bool {
return len(word) < g.wordLenMin || len(word) > g.wordLenMax
})
if len(g.dictionary) < MinWordsInDictionary {
return nil, ErrDictionaryTooSmall
}
if g.numWords < MinNumWords {
return nil, ErrNumWordsInvalid

// capitalize all words in the dictionary ahead of time
if g.capitalize {
for idx := range g.dictionary {
r, size := utf8.DecodeRuneInString(g.dictionary[idx])
if r != utf8.RuneError {
g.dictionary[idx] = string(unicode.ToUpper(r)) + g.dictionary[idx][size:]
}
}
}

if g.numWords < NumWordsMin {
return nil, ErrNumWordsTooSmall
}
if g.numWords > NumWordsMax {
return nil, ErrNumWordsTooLarge
}
return g, nil
}

0 comments on commit 686e61a

Please sign in to comment.