API Reference#

Installation#

The libary is available from PyPI. You can install it like so:

$ pip install papass

API#

papass is a simple library to generate passphrases.

Everything from the papass module is considered public. Everything else is considered private.

Usage#

First we create two word lists:

>>> wordlist_1 = WordList(["bear", "dog", "duck"])
>>> wordlist_2 = WordList(["duck", "cat"])

Word lists implement Sequence, are sorted, can be written to disk, and read from disk.

>>> wordlist = wordlist_1 + wordlist_2
>>> assert wordlist == WordList(["bear", "dog", "duck", "cat"]), "It deduplicates"
>>> assert list(wordlist) == ["bear", "cat", "dog", "duck"], "It is sorted"
>>>
>>> file_path = "/tmp/my_wordlist.txt"
>>> wordlist.to_file(file_path)
>>> assert wordlist == WordList.from_file(file_path)

Next we create a phrase generator. To do that we need a random source. Here we take the systems most secure random source for simplicity but you can also take the one which requires physical dice to be thrown.

>>> rng = SystemRng()
>>> rpg = PhraseGenerator(wordlist=wordlist, rng=rng, delimiter=" ")

This can now be used to create a random phrase:

>>> num_words = 5
>>> rpg.get_phrase(num_words)
RpgResult(phrase=..., entropy=10.0, entropy_is_guaranteed=True)

The actual phrase is random of course. It could be something like 'dog duck cat duck duck'. The entropy is 10.0 in this example because there are 2**10==4**5 possible phrases made up from 5 words with 4 possibilities each.

The entropy_is_guaranteed=True tells us that the entropy is indeed not lower than expected. Note that in principle it might be possible that there are less possible phrases if e.g. you choose '' (empty string) as the delimiter and some words contain some of the other words.

Consider for example the wordlist foo bar foobar barfoo with num_words=5. Then foobarfoo can come from foobar, foo or from foo, barfoo.

If entropy_is_guaranteed=False this doesn’t necessarily mean that the entropy is lower (and even if, it is probably not much lower). The check relies on a simple heuristic which has the property that True is always correct and False basically means don’t know.

class papass.DiceRng(*, num_sides: int = 6, required_success_probability: float = 0.99)#

Bases: RandomNumberGeneratorBase

Random number generator relying on the user to throw physical dice.

__init__(*, num_sides: int = 6, required_success_probability: float = 0.99)#

Create a DiceRng.

Parameters:
  • num_sides – Number of sides of the dice.

  • required_success_probability – The minimal required probability that randbelow does not reject a roll. If upper is a power of num_sides this probability is always 100%. But in general the number of required rolls increases with this probability.

randbelow(upper: int) int#

Generate random integers i with 0 <= i < upper.

If the dice are fair (all sides occur with the same probability) and the rolls are independent the distribution of i is uniform.

class papass.PhraseGenerator(*, wordlist: WordList, rng: RandomNumberGeneratorBase, delimiter: str = ' ')#

Bases: object

Generate phrases from a wordlist using a random number generator.

__init__(*, wordlist: WordList, rng: RandomNumberGeneratorBase, delimiter: str = ' ')#

Create a random phrase generator.

Parameters:
  • wordlist – The words to draw from.

  • rng – The random source to be used to draw words.

  • delimiter – At most a single character to be put between the generated words.

__weakref__#

list of weak references to the object

get_phrase(count: int) RpgResult#

Generate a random phrase.

The phrase is generated by successive applications of rng.choice to the wordlist.

class papass.RandomNumberGeneratorBase#

Bases: ABC

Base for all random number generators.

__weakref__#

list of weak references to the object

choice(items: Sequence[T]) T#

Return a random item from items.

The choices are determined by consecutive calls to randbelow which determines the index of the item to be chosen.

abstract randbelow(upper: int) int#

Return a random integer i with 0 <= i < upper.

class papass.RpgResult(phrase: str, entropy: float, entropy_is_guaranteed: bool)#

Bases: object

Represents the result of random phrase generation.

__eq__(other)#

Return self==value.

__hash__ = None#
__init__(phrase: str, entropy: float, entropy_is_guaranteed: bool) None#
__repr__()#

Return repr(self).

__weakref__#

list of weak references to the object

class papass.SystemRng#

Bases: RandomNumberGeneratorBase

Random number generator using the most secure rng of the operating system.

randbelow(upper: int) int#

Get a random integer i with 0 <= i < upper.

i is uniformly distributed.

class papass.WordList(words: Iterable[str] = [], *, min_word_size: int = 1, max_word_size: int | None = None, remove_leading_digits: bool = False)#

Bases: Sequence[str]

Represents an sorted sequence of unique words.

Internally the list of words is deduplicated and sorted (via sorted).

Example#

>>> wordlist = WordList(["c", "b", "a"])
>>> wordlist
WordList(['a', 'b', 'c'])
>>> assert wordlist[0] == "a"
>>> assert list(wordlist) == ["a", "b", "c"]
>>> assert wordlist == WordList(["a", "b", "c"])
__add__(other: WordList) WordList#
__add__(other: list) WordList

Combine two word lists to a new word list made of the union of their words.

If the second summand is a list of words it behaves as if this list was converted to a word list first.

__eq__(other: object) bool#

Two word lists are equal if they contain the same words.

__getitem__(index: int) str#
__getitem__(index: slice) WordList

Get a word at an index or a new word list from a slice.

__hash__ = None#
__init__(words: Iterable[str] = [], *, min_word_size: int = 1, max_word_size: int | None = None, remove_leading_digits: bool = False)#

Construct a wordlist from words.

Parameters:
  • words – Words to construct wordlist from.

  • min_word_size – Filter out words which are shorter than this.

  • max_word_size – Filter out words which are longer than this. None means no filtering.

  • trim_leading_digits – Some word lists contain lines like 12345  someword. If True we just read someword.

__len__() int#

Return the number of words.

__repr__() str#

A string representation which could be used to initialize an equivalent word list.

__weakref__#

list of weak references to the object

static from_file(file_path: Path | str, **options)#

Construct a wordlist from a file of words (newline separated).

The options are the same as those for __init__.

to_file(file_path: Path | str) None#

Write this wordlist to a file (overwrites if file exists).