Minimal Python reference implementation

The password generation algorithm used in this application is intentionally simple and transparent. Below is a very simplified Python reference implementation demonstrating how dice faces, directions and dice order are combined into a large number and converted into a password.

This version omits input/output validation and other safeguards present in the application. Nevertheless, it is fully functional and reflects the core algorithm used by dicendo.

Its purpose is to make the algorithm easy to inspect and independently verify. For the same inputs, it produces exactly the same outputs as the application.

#!/usr/bin/python3
from math import factorial, floor, log
import re


def lehmer(permutation):
    n = len(permutation)
    lehmer_code = [0] * n

    for i in range(n):
        count = 0
        for j in range(i + 1, n):
            if permutation[j] < permutation[i]:
                count += 1
        lehmer_code[i] = count

    n = len(lehmer_code)
    lehmer_number = 0

    for i in range(n):
        lehmer_number += lehmer_code[i] * factorial(n - 1 - i)
    return lehmer_number


ALPH = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()<>-_=+;:,./?"

# faces = "551421565161262454131223114221644461"
# directions = ""
# order_str = ""
faces = "646512242554"
directions = "WWENSNWESESE".translate(str.maketrans("NESWnesw", "01230123"))
order_str = "12-3-9-6-4-10-8-11-7-5-2-1"

rnd_num = 0

order = []
if order_str != "":
    order = [eval(i) for i in re.split("[-+*/=:;., ]", order_str)]
    rnd_num = lehmer(order)

for f in faces:
    rnd_num = 6 * rnd_num + (eval(f) % 6)

for d in directions:
    rnd_num = 4 * rnd_num + eval(d)

eff_len = floor(
    log(
        factorial(len(order)) * (6 ** len(faces)) * (4 ** len(directions)),
        len(ALPH)
    )
)

passwd = ""
for _ in range(eff_len):
    passwd = ALPH[rnd_num % len(ALPH)] + passwd
    rnd_num = rnd_num // len(ALPH)

print(passwd)