FA-72706 / Check-digit algorithms / Open access
Luhn mod N folds addends in base ten · case 01
Codes containing letters in doubled positions receive the wrong check character.
ROOT CAUSE
The addend is folded as addend // 10 + addend % 10, the decimal Luhn rule, instead of in base 36.
VERIFIED REPAIR
Fold every addend in base N: addend // 36 + addend % 36.
Unsuccessful approach: Keeping only addend % 36 drops the carry of doubled codepoints 18 and above.
Case contract
Luhn mod N check-character generation over the base-36 alphabet 0-9a-z (input is lower-cased; empty input or any other character returns None). From the rightmost payload character the factor alternates 2,1,2,...; each addend factor * codepoint is folded as addend // 36 + addend % 36; the check is the alphabet character at (36 - sum % 36) % 36.
Why this case matters
Voucher and licence-key systems protect alphanumeric codes with Luhn mod N check characters.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(s):
A = '0123456789abcdefghijklmnopqrstuvwxyz'
n = len(A)
t = s.lower()
if not t or any(ch not in A for ch in t):
return None
factor = 2
total = 0
for ch in reversed(t):
addend = factor * A.index(ch)
factor = 1 if factor == 2 else 2
total += addend // 10 + addend % 10
return A[(n - total % n) % n]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression ["lyx7g3y"]', ['lyx7g3y'], 'x'], ['regression ["g22"]', ['g22'], 'y'], ['partial-repair ["hn3a6aj"]', ['hn3a6aj'], 'a'], ['control ["1"]', ['1'], 'y'], ['control ["s8zc"]', ['s8zc'], '5'], ['control ["abc-1"]', ['abc-1'], None], ['control [""]', [''], None], ['control ["0"]', ['0'], '0']], [['regression ["i3wknpx64b"]', ['i3wknpx64b'], 'a'], ['regression ["iu2qty"]', ['iu2qty'], 'k'], ['partial-repair ["a5qsqld2"]', ['a5qsqld2'], 'r'], ['control ["1"]', ['1'], 'y'], ['control ["s8zc"]', ['s8zc'], '5'], ['control ["abc-1"]', ['abc-1'], None], ['control [""]', [''], None], ['control ["0"]', ['0'], '0']], [['regression ["60an"]', ['60an'], '9'], ['regression ["bbw4ngt"]', ['bbw4ngt'], 's'], ['partial-repair ["hgvs8gmf0"]', ['hgvs8gmf0'], 'j'], ['control ["1"]', ['1'], 'y'], ['control ["s8zc"]', ['s8zc'], '5'], ['control ["abc-1"]', ['abc-1'], None], ['control [""]', [''], None], ['control ["0"]', ['0'], '0']], [['regression ["nx"]', ['nx'], 'i'], ['regression ["um"]', ['um'], 'x'], ['partial-repair ["0rr"]', ['0rr'], 'q'], ['control ["1"]', ['1'], 'y'], ['control ["s8zc"]', ['s8zc'], '5'], ['control ["abc-1"]', ['abc-1'], None], ['control [""]', [''], None], ['control ["0"]', ['0'], '0']], [['regression ["w35lg7vo1l"]', ['w35lg7vo1l'], 'c'], ['regression ["w"]', ['w'], '7'], ['partial-repair ["yl5unzgy"]', ['yl5unzgy'], '2'], ['control ["1"]', ['1'], 'y'], ['control ["s8zc"]', ['s8zc'], '5'], ['control ["abc-1"]', ['abc-1'], None], ['control [""]', [''], None], ['control ["0"]', ['0'], '0']]]
for label, args, expected in fixtures[N - 1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression ["lyx7g3y"] | i | x | Failed |
| regression ["g22"] | p | y | Failed |
| partial-repair ["hn3a6aj"] | 2 | a | Failed |
| control ["1"] | y | y | Passed |
| control ["s8zc"] | 5 | 5 | Passed |
| control ["abc-1"] | None | None | Passed |
| control [""] | None | None | Passed |
| control ["0"] | 0 | 0 | Passed |
SHA-256 / bf795f1a246d004c0831192bd376ec098c5433afa3e99a25c7e71a8f2d8d0936
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(s):
A = '0123456789abcdefghijklmnopqrstuvwxyz'
n = len(A)
t = s.lower()
if not t or any(ch not in A for ch in t):
return None
factor = 2
total = 0
for ch in reversed(t):
addend = factor * A.index(ch)
factor = 1 if factor == 2 else 2
total += addend % n
return A[(n - total % n) % n]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression ["lyx7g3y"]', ['lyx7g3y'], 'x'], ['regression ["g22"]', ['g22'], 'y'], ['partial-repair ["hn3a6aj"]', ['hn3a6aj'], 'a'], ['control ["1"]', ['1'], 'y'], ['control ["s8zc"]', ['s8zc'], '5'], ['control ["abc-1"]', ['abc-1'], None], ['control [""]', [''], None], ['control ["0"]', ['0'], '0']], [['regression ["i3wknpx64b"]', ['i3wknpx64b'], 'a'], ['regression ["iu2qty"]', ['iu2qty'], 'k'], ['partial-repair ["a5qsqld2"]', ['a5qsqld2'], 'r'], ['control ["1"]', ['1'], 'y'], ['control ["s8zc"]', ['s8zc'], '5'], ['control ["abc-1"]', ['abc-1'], None], ['control [""]', [''], None], ['control ["0"]', ['0'], '0']], [['regression ["60an"]', ['60an'], '9'], ['regression ["bbw4ngt"]', ['bbw4ngt'], 's'], ['partial-repair ["hgvs8gmf0"]', ['hgvs8gmf0'], 'j'], ['control ["1"]', ['1'], 'y'], ['control ["s8zc"]', ['s8zc'], '5'], ['control ["abc-1"]', ['abc-1'], None], ['control [""]', [''], None], ['control ["0"]', ['0'], '0']], [['regression ["nx"]', ['nx'], 'i'], ['regression ["um"]', ['um'], 'x'], ['partial-repair ["0rr"]', ['0rr'], 'q'], ['control ["1"]', ['1'], 'y'], ['control ["s8zc"]', ['s8zc'], '5'], ['control ["abc-1"]', ['abc-1'], None], ['control [""]', [''], None], ['control ["0"]', ['0'], '0']], [['regression ["w35lg7vo1l"]', ['w35lg7vo1l'], 'c'], ['regression ["w"]', ['w'], '7'], ['partial-repair ["yl5unzgy"]', ['yl5unzgy'], '2'], ['control ["1"]', ['1'], 'y'], ['control ["s8zc"]', ['s8zc'], '5'], ['control ["abc-1"]', ['abc-1'], None], ['control [""]', [''], None], ['control ["0"]', ['0'], '0']]]
for label, args, expected in fixtures[N - 1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression ["lyx7g3y"] | 0 | x | Failed |
| regression ["g22"] | y | y | Passed |
| partial-repair ["hn3a6aj"] | b | a | Failed |
| control ["1"] | y | y | Passed |
| control ["s8zc"] | 5 | 5 | Passed |
| control ["abc-1"] | None | None | Passed |
| control [""] | None | None | Passed |
| control ["0"] | 0 | 0 | Passed |
SHA-256 / 7747ed393335e843b42cc56fffa42ff9c432f45e8d2e402c1bb4732f2638345d
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(s):
A = '0123456789abcdefghijklmnopqrstuvwxyz'
n = len(A)
t = s.lower()
if not t or any(ch not in A for ch in t):
return None
factor = 2
total = 0
for ch in reversed(t):
addend = factor * A.index(ch)
factor = 1 if factor == 2 else 2
total += addend // n + addend % n
return A[(n - total % n) % n]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression ["lyx7g3y"]', ['lyx7g3y'], 'x'], ['regression ["g22"]', ['g22'], 'y'], ['partial-repair ["hn3a6aj"]', ['hn3a6aj'], 'a'], ['control ["1"]', ['1'], 'y'], ['control ["s8zc"]', ['s8zc'], '5'], ['control ["abc-1"]', ['abc-1'], None], ['control [""]', [''], None], ['control ["0"]', ['0'], '0']], [['regression ["i3wknpx64b"]', ['i3wknpx64b'], 'a'], ['regression ["iu2qty"]', ['iu2qty'], 'k'], ['partial-repair ["a5qsqld2"]', ['a5qsqld2'], 'r'], ['control ["1"]', ['1'], 'y'], ['control ["s8zc"]', ['s8zc'], '5'], ['control ["abc-1"]', ['abc-1'], None], ['control [""]', [''], None], ['control ["0"]', ['0'], '0']], [['regression ["60an"]', ['60an'], '9'], ['regression ["bbw4ngt"]', ['bbw4ngt'], 's'], ['partial-repair ["hgvs8gmf0"]', ['hgvs8gmf0'], 'j'], ['control ["1"]', ['1'], 'y'], ['control ["s8zc"]', ['s8zc'], '5'], ['control ["abc-1"]', ['abc-1'], None], ['control [""]', [''], None], ['control ["0"]', ['0'], '0']], [['regression ["nx"]', ['nx'], 'i'], ['regression ["um"]', ['um'], 'x'], ['partial-repair ["0rr"]', ['0rr'], 'q'], ['control ["1"]', ['1'], 'y'], ['control ["s8zc"]', ['s8zc'], '5'], ['control ["abc-1"]', ['abc-1'], None], ['control [""]', [''], None], ['control ["0"]', ['0'], '0']], [['regression ["w35lg7vo1l"]', ['w35lg7vo1l'], 'c'], ['regression ["w"]', ['w'], '7'], ['partial-repair ["yl5unzgy"]', ['yl5unzgy'], '2'], ['control ["1"]', ['1'], 'y'], ['control ["s8zc"]', ['s8zc'], '5'], ['control ["abc-1"]', ['abc-1'], None], ['control [""]', [''], None], ['control ["0"]', ['0'], '0']]]
for label, args, expected in fixtures[N - 1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression ["lyx7g3y"] | x | x | Passed |
| regression ["g22"] | y | y | Passed |
| partial-repair ["hn3a6aj"] | a | a | Passed |
| control ["1"] | y | y | Passed |
| control ["s8zc"] | 5 | 5 | Passed |
| control ["abc-1"] | None | None | Passed |
| control [""] | None | None | Passed |
| control ["0"] | 0 | 0 | Passed |
SHA-256 / 7127e651bec052ebb53f1f2a7618ed97f90992cffb92ef166b2942154e2dfb1a
Verification & scope
A deterministic, bounded teaching model of the named scheme under the stated contract; not a certified validator. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:48:40.886675+00:00.
Case digest / 9774d666ac6cca24d748626e618b25d3ecf107e073cce7eae508872008fcd5c0