Skip to content

Commit

Permalink
Fix naming and entropy
Browse files Browse the repository at this point in the history
  • Loading branch information
GGP1 committed Feb 17, 2021
1 parent f6e2dc5 commit d82d2b2
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 16 deletions.
11 changes: 11 additions & 0 deletions example_test.go
Expand Up @@ -66,3 +66,14 @@ func ExampleNewPassphrase() {
// Example output:
// ynuafnezm hvoq asruso jvoe psiro
}

func ExampleKeyspace() {
p := &atoll.Password{
Length: 6,
Levels: []atoll.Level{atoll.Lowercase},
Repeat: false,
}

fmt.Println(atoll.Keyspace(p))
// Output: 3.089157759999998e+08
}
11 changes: 5 additions & 6 deletions passphrase.go
Expand Up @@ -84,7 +84,7 @@ func (p *Passphrase) generate() (string, error) {
}
}

// Initialize secret slice (included words will be appended)
// Initialize secret slice
p.words = make([]string, int(p.Length))
// Defaults
if p.Separator == "" {
Expand All @@ -109,7 +109,7 @@ func (p *Passphrase) generate() (string, error) {

// includeWords randomly inserts included words in the passphrase.
func (p *Passphrase) includeWords() {
// Append included words
// Add included words at the end of the secret
for i, word := range p.Include {
p.words[int(p.Length)-i-1] = word
}
Expand All @@ -121,7 +121,7 @@ func (p *Passphrase) includeWords() {
}
}

// Check if any excluded word is within the secret and (if true) replace it with another random word.
// excludeWords checks if any excluded word is within the secret and (if true) replace it with another random word.
func (p *Passphrase) excludeWords() {
for i, word := range p.words {
for _, excl := range p.Exclude {
Expand Down Expand Up @@ -177,7 +177,7 @@ func SyllableList(p *Passphrase) {
}
}

// Entropy returns the bits of entropy of the passphrase.
// Entropy returns the passphrase entropy in bits.
//
// If the list used is "NoList" the secret must be already generated.
func (p *Passphrase) Entropy() float64 {
Expand All @@ -192,8 +192,7 @@ func (p *Passphrase) Entropy() float64 {
words := strings.Join(p.words, "")
// Take out the separators from the secret length
secretLength := len(words) - (len(p.Separator) * int(p.Length))
// -26- represents the dictionary length (vowels+constants)
return math.Log2(math.Pow(float64(26), float64(secretLength)))
return math.Log2(math.Pow(float64(len(vowels)+len(constants)), float64(secretLength)))
case "WordList":
poolLength = len(atollWords)
case "SyllableList":
Expand Down
27 changes: 18 additions & 9 deletions password.go
Expand Up @@ -107,12 +107,12 @@ func (p *Password) generate() (string, error) {
remaining := int(p.Length) - len(password)

for i := 0; i < remaining; i++ {
c := p.pool[randInt(len(p.pool))]
password = randInsert(password, c)
char := p.pool[randInt(len(p.pool))]
password = randInsert(password, char)

if !p.Repeat {
// Remove element used
p.pool = strings.Replace(p.pool, string(c), "", 1)
p.pool = strings.Replace(p.pool, string(char), "", 1)
}
}

Expand All @@ -122,19 +122,19 @@ func (p *Password) generate() (string, error) {
}

func (p *Password) generatePool() {
var b strings.Builder
var sb strings.Builder
unique := make(map[Level]struct{})

for _, lvl := range p.Levels {
// Ensure that duplicated levels aren't added twice
if _, ok := unique[lvl]; !ok && len(lvl) > 0 {
unique[lvl] = struct{}{}
b.Grow(len(lvl))
b.WriteString(string(lvl))
sb.Grow(len(lvl))
sb.WriteString(string(lvl))
}
}

p.pool = b.String()
p.pool = sb.String()
}

// initPassword creates the password, adds any included word and makes sure that it contains
Expand Down Expand Up @@ -207,7 +207,7 @@ repeat:
return password
}

// validateLevels checks if Exclude contains all the characters of a level that is in Format.
// validateLevels checks if Exclude contains all the characters of a level that is in Levels.
func (p *Password) validateLevels() error {
for _, lvl := range p.Levels {
if len(lvl) < 1 {
Expand Down Expand Up @@ -250,13 +250,17 @@ func (p *Password) validateLevels() error {
return nil
}

// Entropy returns the bits of entropy of the password.
// Entropy returns the password entropy in bits.
func (p *Password) Entropy() float64 {
poolLength := len(p.pool)
if p.pool == "" {
p.generatePool()
poolLength = len(p.pool)

if !p.Repeat {
poolLength -= int(p.Length)
}

// Do not count 2/3 byte characters as they aren't in the pool
for _, excl := range p.Exclude {
if len(string(excl)) != 1 {
Expand All @@ -265,5 +269,10 @@ func (p *Password) Entropy() float64 {
}
}

// Add the characters that were removed from the pool
if !p.Repeat {
poolLength += int(p.Length)
}

return math.Log2(math.Pow(float64(poolLength), float64(p.Length)))
}
2 changes: 1 addition & 1 deletion password_test.go
Expand Up @@ -274,7 +274,7 @@ func TestPasswordEntropy(t *testing.T) {
Exclude: "a1r/ö",
}

expected := 131.09177703355275
expected := 136.65780028329485

got := p.Entropy()
if got != expected {
Expand Down

0 comments on commit d82d2b2

Please sign in to comment.