Skip to content

Instantly share code, notes, and snippets.

@recmo
Last active May 9, 2017 10:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save recmo/7de32ed6a866f4af684788f901de6f6f to your computer and use it in GitHub Desktop.
Save recmo/7de32ed6a866f4af684788f901de6f6f to your computer and use it in GitHub Desktop.
Serial number generator for Neukey's using Damm's algorithm.
#!/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)))
@recmo
Copy link
Author

recmo commented May 9, 2017

$ time ./NeukeySerial.py > serialnumbers.txt
real  0m1.837s
user  0m1.140s
sys   0m0.696s
$ cat serialnumbers.txt | wc -l
100000
$ cat serialnumbers.txt | uniq | wc -l
100000
$ sha3sum ./serialnumbers.txt 
d3c03d2380b9b7371e0458a79fc2bef9df5f14268030924aa477682f ./serialnumbers.txt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment