PAN Validator
PAN Validator
It's 2 AM and the fraud alerts are going off. Transactions are coming through with invalid card numbers - and somehow your system approved them.
How did invalid PANs get past validation? Because someone commented out the Luhn check "temporarily" three months ago. Never again.
The Luhn Algorithm
Hans Peter Luhn invented this checksum formula in 1954. It catches accidental errors - typos, single-digit mistakes, transpositions. It won't stop deliberate fraud (anyone can compute a valid check digit), but it will catch data entry errors.
The Algorithm:
- Starting from the rightmost digit (the check digit), double every second digit
- If doubling produces a number greater than 9, subtract 9 (equivalent to summing the digits)
- Sum all the digits
- If the total is divisible by 10, the number is valid
Example: 4532015112830366
Position: 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
↑ rightmost
Digit: 4 5 3 2 0 1 5 1 1 2 8 3 0 3 6 6
Double?: ×2 ×2 ×2 ×2 ×2 ×2 ×2 ×2
Result: 8 5 6 2 0 1 10 1 2 2 16 3 0 3 12 6
After -9: 8 5 6 2 0 1 1 1 2 2 7 3 0 3 3 6
Sum: 8+5+6+2+0+1+1+1+2+2+7+3+0+3+3+6 = 50
50 % 10 = 0 → Valid!
The IIN (Issuer Identification Number)
The first 6-8 digits of a PAN identify the card issuer:
First Digit(s) Network
─────────────── ───────
4 Visa
51-55 Mastercard
2221-2720 Mastercard (newer range)
34, 37 American Express
6011, 65 Discover
62 UnionPay
For this problem, extract the first 6 digits as the IIN (the traditional BIN length - Bank Identification Number).
What You're Building
// PANInfo contains validation results and extracted information from a PAN.
type PANInfo struct {
Valid bool // True if PAN passes Luhn check
PAN string // The original PAN (for reference)
IIN string // First 6 digits (Issuer Identification Number)
CheckDigit int // The last digit (Luhn check digit)
Length int // Total length of the PAN
}
// ValidatePAN validates a Primary Account Number and extracts key information.
// It performs Luhn validation and extracts the IIN.
//
// Rules:
// - PAN must be 13-19 digits (industry standard range)
// - All characters must be digits (0-9)
// - Must pass Luhn check
//
// Returns PANInfo with Valid=false if any rule fails.
// The other fields are populated regardless of validity.
func ValidatePAN(pan string) PANInfo
Behavior
Validation Rules
- Length check: PAN must be 13-19 characters
- Digit check: Every character must be '0'-'9'
- Luhn check: Must pass the Luhn algorithm
Field Extraction
Regardless of validity:
IIN: First 6 digits (or entire PAN if shorter than 6)CheckDigit: Last digit as integerLength: Total character count
Examples
ValidatePAN("4532015112830366")
// → PANInfo{
// Valid: true,
// PAN: "4532015112830366",
// IIN: "453201",
// CheckDigit: 6,
// Length: 16,
// }
ValidatePAN("4532015112830367") // Wrong check digit
// → PANInfo{
// Valid: false,
// PAN: "4532015112830367",
// IIN: "453201",
// CheckDigit: 7,
// Length: 16,
// }
ValidatePAN("123") // Too short
// → PANInfo{
// Valid: false,
// PAN: "123",
// IIN: "123",
// CheckDigit: 3,
// Length: 3,
// }
ValidatePAN("4532A15112830366") // Non-digit
// → PANInfo{
// Valid: false,
// PAN: "4532A15112830366",
// IIN: "4532A1", // Still extract what's there
// CheckDigit: 6,
// Length: 16,
// }
Test PANs
The payment industry uses specific test PAN ranges:
Visa: 4532015112830366, 4916338506082832
Mastercard: 5425233430109903, 5114496353984312
Amex: 378282246310005, 371449635398431
Discover: 6011000400000000, 6011111111111117
These are specifically designated for testing and should never be used in production.
Why This Matters
- Data Quality: Catch typos before they hit the network
- Fraud Prevention: Invalid PANs are a red flag
- Network Fees: Some networks charge for invalid requests
- Debugging: Quickly identify malformed test data
When a transaction fails with "Invalid Card Number" (DE39='14'), the first thing to check is Luhn.
Edge Cases to Consider
- Leading zeros: "0000123456789012" is valid (test PANs exist with leading zeros)
- All same digits: "1111111111111117" - valid Luhn (sum=16, but wait, we double alternating...)
- Minimum length: 13 digits (some older cards)
- Maximum length: 19 digits
- Empty string: Invalid
Hints (only if stuck)
<details> <summary>Hint 1: Processing direction</summary>
Process the PAN right-to-left. The check digit (rightmost) is position 1, and you double positions 2, 4, 6, etc.
for i := len(pan) - 1; i >= 0; i-- {
// ...
}
</details>
<details> <summary>Hint 2: The doubling trick</summary>
When you double a digit and get > 9, subtract 9. This is equivalent to summing the two digits:
- 6 × 2 = 12 → 1 + 2 = 3 → same as 12 - 9 = 3
The subtraction is faster than string manipulation.
</details>
<details> <summary>Hint 3: Alternation tracking</summary>
Use a boolean to track which position you're at:
double := false // Start false, first digit is not doubled
for i := len(pan) - 1; i >= 0; i-- {
// process digit
double = !double // Toggle for next iteration
}
</details>