Skip to content

Instantly share code, notes, and snippets.

@donarb
Last active February 16, 2016 05:29
Show Gist options
  • Select an option

  • Save donarb/a8e9c28336d2f2972617 to your computer and use it in GitHub Desktop.

Select an option

Save donarb/a8e9c28336d2f2972617 to your computer and use it in GitHub Desktop.

Revisions

  1. donarb revised this gist Feb 16, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion verhoeff_alpha.py
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,7 @@
    #!/usr/bin/env python

    """
    Python derivative of alphanumeric derivative of Verhoeff check digit algorithm.
    Python port of alphanumeric derivative of Verhoeff check digit algorithm.
    Ported from: https://gist.github.com/mwgamera/1088656
    """
  2. donarb created this gist May 8, 2015.
    124 changes: 124 additions & 0 deletions verhoeff_alpha.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,124 @@
    #!/usr/bin/env python

    """
    Python derivative of alphanumeric derivative of Verhoeff check digit algorithm.
    Ported from: https://gist.github.com/mwgamera/1088656
    """

    N = 18
    N2 = N * 2

    class Verhoeff(object):

    def __init__(self):

    # Multiplication table
    self.d18_op = [0 for i in xrange(N2*N2)]
    for i in xrange(N):
    for j in xrange(N):
    self.d18_op[N2*i+j] = (i + j) % N
    for i in xrange(N):
    for j in xrange(N, N2):
    self.d18_op[N2*i+j] = N + (i + j) % N
    for i in xrange(N, N2):
    for j in xrange(N):
    self.d18_op[N2*i+j] = N + (i - j) % N
    for i in xrange(N, N2):
    for j in xrange(N, N2):
    self.d18_op[N2*i+j] = (N + i - j) % N

    # Inverse table
    self.d18_inv = [0 for i in xrange(N2)]
    for i in xrange(1, N):
    self.d18_inv[i] = N - i
    for i in xrange(N, N2):
    self.d18_inv[i] = i

    # Permutation table
    self.perm = [[] for i in xrange(N2)]
    p = [29,0,32,11,35,20,7,27,2,4,19,28,30,1,5,12,3,9,16,
    22,6,33,8,24,26,21,14,10,34,31,15,25,17,13,23,18]
    b = [False for i in xrange(len(p))]
    i = 0
    while i < len(b):
    h = [None]
    c = h
    ln = 0
    while not b[i]:
    cc = [None, p[i]]
    c[0] = cc
    c = cc
    b[i] = True
    i = p[i]
    ln += 1
    c[0] = h[0]
    for j in xrange(ln):
    pp = [0 for x in xrange(ln)]
    self.perm[c[1]] = pp
    for k in xrange(ln):
    pp[k] = c[1]
    c = c[0]
    c = c[0]
    while i < len(b) and b[i] == True:
    i += 1

    # Alphanumeric to numeric conversion table
    self.a2i = [0xff for i in xrange(256)]
    for i in xrange(0x30, 0x3a): self.a2i[i] = i - 0x30
    for i in xrange(0x41, 0x5b): self.a2i[i] = i - 0x41 + 10
    for i in xrange(0x61, 0x7b): self.a2i[i] = i - 0x61 + 10

    # Numeric to alphanumeric conversion table
    self.i2a = [0 for i in xrange(N2)]
    for i in xrange(0, 10): self.i2a[i] = i + 0x30
    for i in xrange(10, N2): self.i2a[i] = i + 0x41 - 10

    def op(self, i, j):
    """ Group operation """
    return self.d18_op[N2*i+j]

    def nperm(self, i , n):
    """ Compute n-th application of the permutation """
    return self.perm[i][n % len(self.perm[i])]

    def is_valid(self, s):
    return self.verify(s) == 0

    def verify(self, s):
    """ Verify correctness of check digit, returns 0 if correct """
    i = 0
    c = 0
    for ch in reversed(s):
    ch = self.a2i[ord(ch) & 0xff]
    if ch != 0xff:
    c = self.op(c, self.nperm(ch, i))
    i += 1
    return c

    def create(self, s):
    """ Create a new check digit """
    i = 1
    c = 0
    for ch in reversed(s):
    ch = self.a2i[ord(ch) & 0xff]
    if ch != 0xff:
    c = self.op(c, self.nperm(ch, i))
    i += 1
    return self.i2a[self.d18_inv[c]]

    def append(self, s):
    """ Append check digit to the given string """
    return s + chr(self.create(s))

    def main():

    v = Verhoeff()
    assert v.create('ABCDEF') == 67
    assert v.append('123ABCDEF') == '123ABCDEFD'
    assert v.append('ABCDEF') == 'ABCDEFC'

    assert v.verify('ABCDEFC') == 0

    if __name__ == '__main__':
    main()