Last active
May 9, 2017 10:56
-
-
Save recmo/7de32ed6a866f4af684788f901de6f6f to your computer and use it in GitHub Desktop.
Serial number generator for Neukey's using Damm's algorithm.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
from os import urandom | |
# Damm's weakly totally antisymetric quasigroup of order 10 | |
# https://en.wikipedia.org/wiki/Damm_algorithm | |
Damm = [ | |
[0, 3, 1, 7, 5, 9, 8, 6, 4, 2], | |
[7, 0, 9, 2, 1, 5, 4, 8, 6, 3], | |
[4, 2, 0, 6, 8, 7, 1, 3, 5, 9], | |
[1, 7, 5, 0, 9, 8, 3, 4, 2, 6], | |
[6, 1, 2, 3, 0, 4, 5, 9, 7, 8], | |
[3, 6, 7, 4, 2, 0, 9, 5, 8, 1], | |
[5, 8, 6, 9, 7, 2, 0, 1, 3, 4], | |
[8, 9, 4, 5, 3, 6, 2, 0, 1, 7], | |
[9, 4, 3, 8, 6, 1, 7, 2, 0, 5], | |
[2, 5, 8, 1, 4, 3, 6, 7, 9, 0] | |
] | |
def groupOperation(a, b): | |
return Damm[a][b] | |
def groupProduct(digits, initial = 0): | |
interim = initial | |
for digit in digits: | |
interim = groupOperation(interim, digit) | |
return interim | |
def addCheckDigit(digits): | |
return digits + [groupProduct(digits)] | |
def checkDigits(digits): | |
return groupProduct(digits) == 0 | |
def toDigits(number, base = 10): | |
digits = [] | |
while number > 0: | |
digits.append(number % base) | |
number = number // base | |
return digits[::-1] | |
def fromDigits(digits, base = 10): | |
number = 0 | |
for digit in digits: | |
number *= base | |
number += digit | |
return number | |
def addCheck(number): | |
return fromDigits(addCheckDigit(toDigits(number))) | |
def check(number): | |
return checkDigits(toDigits(number)) | |
# Test algorithms | |
assert addCheck(572) == 5724 | |
assert check(5724) | |
assert not check(5742) | |
def randomNumber(max): | |
assert max < 2 ** 32 | |
seed = int.from_bytes(urandom(64), byteorder='big') | |
return seed % max | |
def shuffle(list): | |
n = len(list) | |
for i in range(n - 1): | |
j = i + randomNumber(n - i) | |
list[i], list[j] = list[j], list[i] | |
yield list[i] | |
yield list[n - 1] | |
def formatGroups(number, digits = 6, groupSize = 3, separator = "."): | |
numGroups = (digits + (groupSize - 1)) // groupSize | |
groups = toDigits(number, 10 ** groupSize) | |
groups = ([0] * (numGroups - len(groups))) + groups | |
groupFormat = "{:0>" + str(groupSize) +"}" | |
groups = [groupFormat.format(x) for x in groups] | |
return separator.join(groups) | |
# Print random permutation of all serial numbers | |
for n in shuffle(list(range(10**5))): | |
print(formatGroups(addCheck(n))) |
Author
recmo
commented
May 9, 2017
•
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment