Skip to content

Instantly share code, notes, and snippets.

@averykhoo
Created March 7, 2019 02:05
Show Gist options
  • Save averykhoo/d373123209591f98def15c8be8de315d to your computer and use it in GitHub Desktop.
Save averykhoo/d373123209591f98def15c8be8de315d to your computer and use it in GitHub Desktop.
# https://en.wikipedia.org/wiki/National_Registration_Identity_Card
# http://www.ngiam.net/NRIC/
# http://www.ngiam.net/NRIC/NRIC_numbers.pdf
import random
weights = [2, 7, 6, 5, 4, 3, 2]
local_alphas = 'JZIHGFEDCBA'
foreign_alphas = 'XWUTRQPNMLK'
alt_weights = [9, 4, 5, 6, 7, 8, 9]
alt_local_alphas = 'JABCDEFGHIZ'
def checksum_alpha(digits, init_alpha='S'):
# sanity check
assert len(digits) == 7
# dot product
checksum = sum(weight * int(digit) for weight, digit in zip(weights, digits))
# offset based on initial letter
if init_alpha.lower() in 'sf':
checksum += 0
elif init_alpha.lower() in 'tg':
checksum += 4
else:
pass
# return from appropriate alphabet
if init_alpha.lower() in 'st':
return local_alphas[checksum % 11]
elif init_alpha.lower() in 'fg':
return foreign_alphas[checksum % 11]
else:
return None
def validate(ic):
# cleanup
ic = ic.strip()
# catch malformed input
try:
return ic[8] == checksum_alpha(ic[1:8], ic[0])
except:
return None
def generate(year=None, local=None):
# randomize unknown year
if year is None:
year = random.choice(range(1901, 2020))
else:
assert 1799 < year < 2100
# randomize unknown local/foreign
if local is None:
local = bool(random.getrandbits(1))
# first two digits
if local:
if year > 1967:
digits = str(year)[-2:]
else:
# in reality there's probably some distribution over the other digits too
digits = random.choice('01') + str(random.randint(0, 9))
else:
# much is unknown about fins, this seems incorrect
if year > 2008:
digits = random.choice('45678901') + str(random.randint(0, 9))
else:
digits = random.choice('23') + str(random.randint(0, 9))
# now append more digits
digits += str(random.randint(0, 99999)).rjust(5, '0')
# find first alphabet
init_alpha = '------------------sst' if local else '------------------ffg'
init_alpha = init_alpha[year // 100]
# last alphabet and capitalize
final_alpha = checksum_alpha(digits, init_alpha)
out = init_alpha + str(digits) + final_alpha
return out.upper()
if __name__ == '__main__':
print validate('S0000001I') # Yusof bin Ishak
print validate('S0000002G') # Lee Kuan Yew
print validate('S0000003E') # Kwa Geok Choo
print checksum_alpha('9876543', init_alpha='S')
print checksum_alpha('3456789', init_alpha='G')
print generate(2019, True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment