Số thẻ ngân hàng tự phát hiện được khi gõ sai nhờ thuật toán Luhn: chữ số cuối cùng của số thẻ là chữ số kiểm tra, được chọn sao cho một phép tính đơn giản trên toàn bộ dãy số cho ra kết quả chia hết cho 10. Gõ nhầm một chữ số bất kỳ, hoặc đảo chỗ hai chữ số liền nhau (trừ cặp 09 và 90), phép tính sẽ không còn chia hết cho 10, và trang thanh toán báo lỗi ngay trước khi gửi đi.
Thuật toán Luhn từ đâu ra
Thuật toán mang tên Hans Peter Luhn, kỹ sư người Đức làm việc cho IBM ở Mỹ. Ông nộp đơn xin bằng sáng chế cho một "máy kiểm tra số" năm 1954, được cấp năm 1960. Chiếc máy ban đầu là thiết bị cơ khí cầm tay, ý tưởng là giúp nhân viên nhập liệu phát hiện số bị chép sai. Luhn còn được biết đến với nhiều công trình về xử lý văn bản và truy tìm thông tin; thuật toán kiểm tra số chỉ là một trong số đó, nhưng là thứ sống dai nhất.
Khi thẻ tín dụng phổ biến từ thập niên 1960–1970, các tổ chức thẻ chọn thuật toán Luhn làm chữ số kiểm tra. Ngày nay nó được ghi trong tiêu chuẩn quốc tế ISO/IEC 7812 về số thẻ định danh. Cùng thuật toán còn dùng cho số IMEI của điện thoại di động (15 chữ số, xem bằng cách bấm *#06#), số bảo hiểm xã hội của Canada và nhiều mã số khác.
Cách tính Luhn bằng tay: ví dụ từng bước
Quy tắc kiểm tra một dãy số (đã có chữ số kiểm tra ở cuối):
- Đi từ phải sang trái. Chữ số cuối cùng giữ nguyên, chữ số thứ hai từ phải nhân đôi, thứ ba giữ nguyên, thứ tư nhân đôi, cứ xen kẽ như vậy.
- Kết quả nhân đôi nào lớn hơn 9 thì trừ đi 9 (tương đương cộng hai chữ số của nó: 16 thành 1 + 6 = 7).
- Cộng tất cả lại. Nếu tổng chia hết cho 10, dãy số hợp lệ.
Ví dụ tính chữ số kiểm tra cho dãy 7992739871 (dãy ví dụ kinh điển trong sách vở). Vì sẽ thêm một chữ số vào cuối, chữ số 1 hiện tại sẽ đứng thứ hai từ phải, nên được nhân đôi:
| Chữ số (từ phải sang) | Nhân đôi? | Giá trị |
|---|---|---|
| 1 | có | 2 |
| 7 | không | 7 |
| 8 | có | 16 → 7 |
| 9 | không | 9 |
| 3 | có | 6 |
| 7 | không | 7 |
| 2 | có | 4 |
| 9 | không | 9 |
| 9 | có | 18 → 9 |
| 7 | không | 7 |
Tổng: 2 + 7 + 7 + 9 + 6 + 7 + 4 + 9 + 9 + 7 = 67. Muốn tổng chia hết cho 10, cần cộng thêm 3. Chữ số kiểm tra là 3, số đầy đủ là 79927398713. Kiểm lại: 67 + 3 = 70, chia hết cho 10.
Thử gõ sai một chữ số
Giả sử gõ nhầm 79927398713 thành 79927598713 (chữ số 3 thành 5, ở vị trí được nhân đôi). Giá trị ở vị trí đó đổi từ 6 thành 10 → 1, tổng đổi từ 70 thành 65. Không chia hết cho 10, máy báo sai. Gõ nhầm ở vị trí không nhân đôi thì tổng lệch đúng bằng độ lệch của chữ số, cũng không thể còn chia hết cho 10.
Luhn bắt được lỗi nào, bỏ sót lỗi nào
Hai loại lỗi nhập liệu phổ biến nhất là sai một chữ số và đảo chỗ hai chữ số liền nhau (gõ 37 thành 73). Luhn được thiết kế để bắt cả hai.
- Sai một chữ số: bắt được 100%. Ở vị trí giữ nguyên, đổi chữ số thì giá trị đổi ngay. Ở vị trí nhân đôi, phép "nhân 2 rồi trừ 9 nếu lớn hơn 9" biến 0, 1, 2… 9 thành 0, 2, 4, 6, 8, 1, 3, 5, 7, 9, không có hai chữ số nào cho cùng giá trị, nên đổi chữ số cũng làm đổi tổng.
- Đảo hai chữ số liền nhau: bắt được gần hết, trừ cặp 0 và 9. Đổi 09 thành 90 cho cùng tổng, vì 0 + 9 (nhân đôi 9 thành 9) bằng 0 (nhân đôi 0) + 9.
- Lỗi "cặp đôi" (gõ 22 thành 55, 33 thành 66, 44 thành 77): Luhn không bắt được.
- Nhiều lỗi cùng lúc: có thể bù trừ nhau. Khoảng một phần mười các dãy gõ sai ngẫu nhiên vẫn tình cờ qua được phép kiểm.
| Cách kiểm | Sai một chữ số | Đảo hai chữ số liền nhau |
|---|---|---|
| Cộng thẳng các chữ số, chia hết cho 10 | Bắt hết | Không bắt được trường hợp nào |
| Luhn | Bắt hết | Bắt hết, trừ 09 ↔ 90 |
| Verhoeff (1969), Damm (2004) | Bắt hết | Bắt hết |
Chỉ cộng thẳng các chữ số thì đảo chỗ không làm đổi tổng, nên vô dụng với lỗi đảo. Mẹo "nhân đôi xen kẽ" của Luhn chính là để phân biệt vị trí. Nhà toán học Hà Lan Jacobus Verhoeff năm 1969 và H. Michael Damm năm 2004 đưa ra những thuật toán bắt được mọi lỗi đảo chỗ, nhưng phải dùng bảng tra phức tạp hơn. Luhn tồn tại đến hôm nay vì đủ tốt và tính nhẩm được.
Đọc cấu trúc một số thẻ
Số thẻ thanh toán thường dài 16 chữ số (có loại 15 hoặc 19). Theo ISO/IEC 7812, nó gồm ba phần:
- Mã tổ chức phát hành (IIN, còn gọi BIN): 6 đến 8 chữ số đầu, cho biết tổ chức thẻ và ngân hàng phát hành. Chữ số đầu tiên đã nói nhiều: 4 là Visa, 51–55 và dải 2221–2720 là Mastercard, 34 và 37 là American Express, 3528–3589 là JCB. Thẻ nội địa Napas ở Việt Nam bắt đầu bằng 9704.
- Số tài khoản cá nhân: phần giữa, do ngân hàng cấp.
- Chữ số kiểm tra: chữ số cuối, tính bằng Luhn.
Nhờ phần đầu, trang thanh toán có thể hiện logo Visa hay Mastercard ngay khi bạn gõ vài số đầu. Nhờ chữ số cuối, trang báo "số thẻ không hợp lệ" mà không cần hỏi ngân hàng.
Luhn không phải là bảo mật
Đây là điểm hay bị hiểu nhầm. Thuật toán Luhn công khai, ai cũng tính được. Nó chỉ trả lời câu hỏi "dãy số này có bị gõ nhầm không", chứ không trả lời "thẻ này có thật không" hay "người này có phải chủ thẻ không". Một số thẻ qua được phép kiểm Luhn chỉ là một dãy số đúng định dạng.
Việc xác thực thật sự nằm ở các lớp khác: ngày hết hạn, mã CVV/CVC ở mặt sau, mã OTP gửi về điện thoại, xác thực sinh trắc học của ứng dụng ngân hàng, và hệ thống chấm điểm rủi ro của ngân hàng phát hành. Lời khuyên vì thế không đổi: không đưa ảnh hai mặt thẻ, mã CVV hay mã OTP cho bất kỳ ai, kể cả người tự xưng là nhân viên ngân hàng.
Góc nhìn hôm nay: tự kiểm một dãy số trong 30 giây
Thử với số IMEI điện thoại của chính mình: bấm *#06#, lấy 15 chữ số, nhân đôi các chữ số ở vị trí chẵn tính từ phải (thứ 2, 4, 6…), trừ 9 với kết quả lớn hơn 9, cộng tất cả. Tổng sẽ chia hết cho 10. Đây là cách hay để thấy một thuật toán hơn 60 năm tuổi vẫn nằm trong túi mỗi người.
Với người làm phần mềm, có một điều nên nhớ: kiểm Luhn ngay trên biểu mẫu giúp người dùng sửa lỗi gõ sớm, giảm giao dịch hỏng; nhưng đừng bao giờ coi qua được Luhn là đủ để chấp nhận thanh toán. Ai muốn tìm hiểu sâu hơn về họ thuật toán này có thể đọc về "check digit" và các thuật toán Verhoeff, Damm trong sách nhập môn về mã phát hiện lỗi.
Câu hỏi thường gặp
Thuật toán Luhn là gì?
Là cách tính chữ số kiểm tra do Hans Peter Luhn (IBM) đưa ra năm 1954: nhân đôi xen kẽ các chữ số từ phải sang, trừ 9 nếu kết quả lớn hơn 9, cộng tất cả lại; dãy hợp lệ khi tổng chia hết cho 10. Nó dùng cho số thẻ ngân hàng, số IMEI và nhiều mã số khác.
Chữ số cuối của số thẻ ngân hàng có ý nghĩa gì?
Đó là chữ số kiểm tra, được chọn để toàn bộ số thẻ qua được phép tính Luhn. Nhờ nó, trang thanh toán phát hiện ngay khi bạn gõ nhầm một chữ số hoặc đảo chỗ hai chữ số liền nhau.
Số thẻ hợp lệ theo Luhn có phải là thẻ thật không?
Không. Luhn chỉ kiểm tra định dạng để bắt lỗi gõ nhầm, ai cũng tính được. Thẻ có thật và giao dịch có hợp lệ hay không do ngân hàng xác thực qua ngày hết hạn, mã CVV, OTP và các lớp bảo mật khác.
Số thẻ Visa, Mastercard, Napas bắt đầu bằng số mấy?
Thẻ Visa bắt đầu bằng 4; Mastercard bằng 51–55 hoặc dải 2221–2720; American Express bằng 34 hoặc 37; JCB bằng 3528–3589. Thẻ nội địa Napas ở Việt Nam bắt đầu bằng 9704.
Thuật toán Luhn không phát hiện được lỗi nào?
Nó không phát hiện được việc đảo chỗ cặp 09 thành 90 (và ngược lại), các lỗi cặp đôi như 22 thành 55 hay 33 thành 66, và một số trường hợp nhiều lỗi bù trừ nhau. Mọi lỗi sai đúng một chữ số thì đều bị phát hiện.