Fast, privacy-first Singapore NRIC & FIN verification with reverse unknown-digit deduction, full weighted-sum Mod-11 math audits, and compliant developer test data generation. Runs 100% in your browserβno identity numbers ever leave your device.
Test any Singapore Citizen / PR (S, T) or Foreigner Pass / FIN (F, G, M) number. Real-time evaluation runs completely in your browser β zero network requests or logs.
| Digit Pos | D1 | D2 | D3 | D4 | D5 | D6 | D7 | Series Offset |
|---|
Have a partially redacted or smudged NRIC? Enter ?, *, or _ for unknown digits. Using modular inverse arithmetic mod 11, this engine calculates all mathematically valid candidates that produce the target checksum.
Audit thousands of NRICs simultaneously. Paste text, enter one per line, or drop a CSV. Instantly view validation metrics and export clean valid/invalid lists.
Generate valid synthetic NRIC / FIN numbers for software testing, mock QA databases, and form validation benchmarking in compliance with privacy best practices.
Singapore NRIC and FIN algorithms utilize a weighted modulus-11 checksum. Each of the 7 central digits is multiplied by fixed prime-derived weights, offset by series bias, and mapped to specific check characters.
The 7 numerical digits \(d_1, d_2, d_3, d_4, d_5, d_6, d_7\) are multiplied respectively by:
An initial series offset \(O\) is added to the dot product sum:
| Remainder | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| S & T Map | J | Z | I | H | G | F | E | D | C | B | A |
| F & G Map | X | W | U | T | R | Q | P | N | M | L | K |
| M Map | X | W | U | T | R | Q | P | N | J | L | K |
Because 11 is prime and every weight \(w \in \{2, 3, 4, 5, 6, 7\}\) is coprime with 11 (\(\gcd(w, 11) = 1\)), the linear congruence \(w \cdot d \equiv C \pmod{11}\) always has exactly one unique solution modulo 11. If that solution is between 0 and 9, the missing digit is uniquely determined. If it equals 10, no valid digit exists. Hence, an NRIC with 1 missing digit can never have ambiguous possibilities.
Fine-tune verification rules, toggle strict series era validation, or copy ready-to-run code snippets for JavaScript, TypeScript, and Python.
export function validateNRIC(input) {
if (!input || typeof input !== 'string') return false;
const str = input.trim().toUpperCase();
if (!/^[STFGM]\d{7}[A-Z]$/.test(str)) return false;
const prefix = str[0];
const digits = str.slice(1, 8);
const checkChar = str[8];
const weights = [2, 7, 6, 5, 4, 3, 2];
let sum = (prefix === 'T' || prefix === 'G') ? 4 : (prefix === 'M' ? 3 : 0);
for (let i = 0; i < 7; i++) {
sum += parseInt(digits[i], 10) * weights[i];
}
const remainder = sum % 11;
const stMap = ['J','Z','I','H','G','F','E','D','C','B','A'];
const fgMap = ['X','W','U','T','R','Q','P','N','M','L','K'];
const mMap = ['X','W','U','T','R','Q','P','N','J','L','K'];
const expected = (prefix === 'S' || prefix === 'T')
? stMap[remainder]
: (prefix === 'M' ? mMap[remainder] : fgMap[remainder]);
return checkChar === expected;
}