ขั้นตอนวิธี Luhn เป็นสูตรเลขคณิตสั้น ๆ ที่ตัดสินว่าชุดตัวเลขหนึ่ง ๆ สอดคล้องกันภายในหรือไม่ ด้วยการคูณหลักเว้นหลักและบวกผลลัพธ์ทั้งหมดเข้าด้วยกัน แล้วดูว่าผลรวมหารด้วยสิบลงตัวหรือไม่ มันเป็นเหตุผลที่ฟอร์มชำระเงินร้องเตือนทันทีที่คุณพิมพ์หมายเลขบัตรผิดหนึ่งหลัก โดยที่ยังไม่มีการติดต่อธนาคารใด ๆ บทความนี้อธิบายกลไกของสูตรตั้งแต่ต้น วิธีไล่คำนวณด้วยกระดาษหนึ่งแผ่น และขอบเขตที่สูตรนี้ไม่ได้คุ้มครองอะไรให้คุณเลย
ขั้นตอนวิธี Luhn ทำอะไรกับตัวเลขแต่ละหลัก?
แนวคิดมีเพียงข้อเดียว คือทำให้ตัวเลขทุกหลักมีน้ำหนักไม่เท่ากัน แล้วบังคับให้ผลรวมที่ได้หารด้วยสิบลงตัว หลักที่อยู่ตำแหน่งเว้นตำแหน่งนับจากขวาจะถูกคูณสอง ส่วนหลักที่อยู่ระหว่างนั้นคงค่าเดิมไว้ ถ้าผลคูณของหลักใดเกินเก้า ให้นำตัวเลขสองหลักของผลลัพธ์มาบวกกันจนเหลือหลักเดียว วิธีนี้ทำให้ค่าทุกตัวอยู่ในช่วงศูนย์ถึงเก้าก่อนนำไปรวม
เมื่อรวมครบทุกหลักแล้ว ถ้าผลหารด้วยสิบเหลือเศษศูนย์ ชุดตัวเลขนั้นถือว่า “ผ่าน” ถ้าเหลือเศษเป็นอย่างอื่น ถือว่า “ไม่ผ่าน” และหลักสุดท้ายของหมายเลขบัตรถูกกำหนดขึ้นล่วงหน้าโดยผู้ออกแบบระบบให้เป็นค่าที่ทำให้ผลรวมลงตัวพอดี หลักนี้จึงถูกเรียกว่าหลักตรวจสอบ
ลองคำนวณด้วยมือด้วยหมายเลขสั้นเจ็ดหลัก
เพื่อให้เห็นภาพชัดขึ้น สมมติว่าคุณมีชุดตัวเลขสั้น ๆ เจ็ดหลักคือ 7 9 9 2 7 3 1 แล้วต้องการรู้ว่าชุดนี้สอดคล้องกันหรือไม่ ขั้นตอนที่ทำตามได้ทันทีคือ
- เขียนตัวเลขเรียงจากซ้ายไปขวาโดยไม่ต้องสนใจช่องว่างหรือขีดกลาง
- นับจากหลักขวาสุดเข้ามา ปล่อยหลักขวาสุดไว้ตามเดิม แล้วคูณสองหลักถัดไป ปล่อยหลักถัดไปไว้ แล้วสลับกันแบบนี้จนครบ
- ถ้าผลคูณได้สิบหรือมากกว่า ให้นำตัวเลขสองหลักของผลลัพธ์มาบวกกัน เช่น แปดคูณสองได้สิบหก จึงกลายเป็นหนึ่งบวกหกเท่ากับเจ็ด
- บวกค่าทุกหลักที่ได้เข้าด้วยกัน
- หารผลรวมด้วยสิบ ถ้าลงตัวพอดี ชุดตัวเลขนั้นผ่าน
ลองไล่กับชุดเจ็ดหลักข้างต้นจะได้ผลรวมที่ไม่ลงตัว แสดงว่าชุดนี้ไม่ผ่านการตรวจ ซึ่งเป็นเรื่องปกติของตัวเลขที่ยกขึ้นมาเป็นตัวอย่างโดยไม่ได้ตั้งใจให้ถูกต้อง สังเกตว่าตัวเลขชุดนี้มีเจ็ดหลัก ไม่ใช่หมายเลขบัตรจริง และใช้เพียงเพื่อสาธิตวิธีคิดเท่านั้น
ข้อควรระวังที่ทำให้คนคำนวณพลาดบ่อยมีสองข้อ ข้อแรกคือต้องนับตำแหน่งจากขวาเสมอ ไม่ใช่นับจากซ้าย เพราะตัวเลขหนึ่งชุดที่ยาวเป็นจำนวนคี่หรือคู่จะทำให้หลักที่ถูกคูณสองเลื่อนตำแหน่งกัน ข้อที่สองคือหลักที่คูณสองแล้วได้สิบพอดีจะกลายเป็นหนึ่ง ไม่ใช่ศูนย์ ซึ่งเป็นจุดที่การคำนวณแบบลัดมักเข้าใจผิด
ทำไมหมายเลขบัตรต้องมีหลักตรวจสอบต่อท้าย?
หลักตรวจสอบมีไว้เพื่อจับความผิดพลาดของมนุษย์ ไม่ได้มีไว้ป้องกันการปลอมแปลง การพิมพ์หมายเลขบัตรหนึ่งหลักผิดเป็นความผิดพลาดที่พบได้บ่อยมาก ทั้งจากการอ่านตัวเลขบนบัตรที่สึกหรอ การลอกตัวเลขจากจอภาพ และการพิมพ์บนแป้นตัวเลขที่ไม่มีปุ่มตัวอักษรให้ยึดเป็นหลัก
หากไม่มีหลักตรวจสอบ ระบบจะรับตัวเลขที่พิมพ์ผิดเข้าไปในขั้นตอนถัดไป แล้วต้องรอให้คำขออนุมัติล้มเหลวจึงจะรู้ผล ซึ่งช้ากว่าและทำให้ข้อมูลเสียอยู่ในฐานข้อมูลโดยไม่จำเป็น หลักตรวจสอบช่วยให้ปฏิเสธได้ทันทีในระดับการคำนวณที่เครื่องทำได้เอง โดยไม่ต้องส่งคำขอใด ๆ ออกไป
ในทางกลับกัน ผู้ออกแบบหมายเลขบัตรก็ใช้สูตรเดียวกันนี้ในการคำนวณหลักสุดท้ายให้กับหมายเลขใหม่ทุกใบ เพื่อให้ระบบปลายทางตรวจสอบได้สะดวกนั่นเอง
สลับตำแหน่งหลักแล้วทำไมบางครั้งตรวจไม่เจอ?
หนึ่งในจุดอ่อนที่ควรรู้คือการสลับตำแหน่งของหลักที่อยู่ติดกันจะถูกจับได้ส่วนใหญ่ แต่ไม่ใช่ทั้งหมด และมีกรณีหนึ่งที่หลุดตลอด คือการสลับคู่ที่ค่าต่างกันอยู่สิบพอดี อย่างการสลับระหว่างศูนย์กับเก้า ไปเป็นเก้ากับศูนย์ หรือการสลับระหว่างหนึ่งกับเก้าแบบที่ผลรวมของค่าถ่วงน้ำหนักไม่เปลี่ยน
นอกจากนี้การพิมพ์ผิดสองตำแหน่งพร้อมกันในลักษณะที่ส่วนต่างหักล้างกันพอดีก็ผ่านสูตรไปได้เช่นกัน แม้ว่าโอกาสเกิดขึ้นจะต่ำ แต่สำหรับระบบที่ต้องแม่นยำสูง ความเป็นไปได้ที่ต่ำไม่เท่ากับศูนย์
รายการที่สูตรนี้ไม่จับได้จึงสรุปได้เป็นสองกลุ่ม คือการสลับคู่ที่ผลรวมถ่วงน้ำหนักไม่เปลี่ยน และความผิดพลาดหลายตำแหน่งที่หักล้างกันเอง การรู้ข้อจำกัดเหล่านี้ช่วยให้คุณไม่ตั้งความหวังผิดกับมัน
ผ่านการตรวจแล้วแปลว่าอะไร
คำตอบที่สั้นที่สุดคือ “ผ่านการตรวจ” แปลว่ารูปแบบของชุดตัวเลขสอดคล้องกันในเชิงเลขคณิตเท่านั้น ไม่ได้แปลว่าบัญชีมีอยู่จริง ยังเปิดใช้งานอยู่ หรือเรียกเก็บเงินได้ และไม่ได้แปลว่าหมายเลขนั้นเคยถูกออกให้ใครเลยแม้แต่รายเดียว
เพราะสูตรนี้เปิดเผยต่อสาธารณะและย้อนกลับได้ ใครก็สามารถสร้างชุดตัวเลขที่ผ่านการตรวจได้ภายในเสี้ยววินาที เครื่องมือสร้างข้อมูลทดสอบจึงผลิตหมายเลขที่ผ่านสูตรได้ครั้งละหลายสิบใบโดยไม่ต้องมีความรู้เรื่องการธนาคารเลยแม้แต่น้อย
ด้วยเหตุนี้ระบบรับชำระเงินที่ออกแบบดีจะไม่หยุดอยู่ที่การตรวจผลรวม แต่จะตรวจคำนำหน้าเทียบกับเครือข่ายบัตรที่รองรับ ตรวจความยาวให้ตรงกับเครือข่ายนั้น และเก็บด่านสุดท้ายไว้ที่การอนุมัติจากผู้ออกบัตรเสมอ รายละเอียดของหมายเลขแต่ละเครือข่ายอยู่ในบทความเรื่องรูปแบบหมายเลขบัตรเครดิต
สำหรับนักพัฒนา: ลำดับการตรวจที่ลดงานซ้ำซ้อน
การคำนวณผลรวมเป็นงานที่หนักกว่าการตรวจความยาวและตรวจชนิดของอักขระ ดังนั้นลำดับที่ประหยัดที่สุดคือตรวจสิ่งที่ถูกที่สุดก่อน แล้วค่อยไปหาสิ่งที่แพงกว่า
- ตัดช่องว่างและขีดกลางออกก่อน แล้วปฏิเสธทันทีถ้ายังมีอักขระอื่นนอกจากตัวเลข
- ตรวจความยาวว่าอยู่ในช่วงที่ระบบรองรับจริง เพื่อไม่ให้เสียแรงกับข้อมูลที่ผิดตั้งแต่ต้น
- ตรวจคำนำหน้าเทียบกับรายการเครือข่ายบัตรที่ธุรกิจของคุณรองรับ
- จึงค่อยคำนวณผลรวมตรวจสอบเป็นขั้นสุดท้าย
- ส่งผลลัพธ์กลับเป็นข้อความที่แยกได้ชัดว่าล้มเหลวเพราะเหตุใด ไม่ใช่ข้อความกวม ๆ ข้อความเดียว
อีกข้อที่ควรทำคือแยกส่วนคำนวณหลักตรวจสอบออกจากส่วนตรวจสอบให้เป็นคนละหน้าที่ เพราะเมื่อคุณต้องการสร้างหมายเลขใหม่ คุณจะต้องใช้ส่วนคำนวณเพื่อเติมหลักสุดท้าย ยิ่งแยกชัดเท่าไร การทดสอบทั้งสองทางก็ยิ่งง่ายขึ้นเท่านั้น และอย่าลืมว่าการตรวจฝั่งหน้าเว็บมีไว้เพื่อประสบการณ์ผู้ใช้เท่านั้น การตัดสินใจที่เชื่อถือได้ต้องเกิดที่เซิร์ฟเวอร์เสมอ
ตรวจคำตอบของคุณด้วยเครื่องมือบนเว็บไซต์นี้
ถ้าคุณเพิ่งเขียนสูตรขึ้นมาเองและอยากรู้ว่าคำนวณถูกหรือไม่ เครื่องมือสร้างหมายเลขบัตรบนเว็บไซต์นี้สร้างหมายเลขที่ผ่านการตรวจให้ได้ครั้งละหลายใบ จึงเหมาะสำหรับใช้ยืนยันว่าฟังก์ชันของคุณยอมรับสิ่งที่ควรยอมรับ และสำหรับใช้เป็นข้อมูลนำเข้าในการทดสอบกรณีล้มเหลวด้วย
หมายเลขทุกใบที่เครื่องมือนี้สร้างเป็นข้อมูลเชิงโครงสร้างที่ไม่มีบัญชีรองรับอยู่จริง ไม่เคยถูกออกให้กับใคร และใช้ได้เฉพาะกับงานทดสอบซอฟต์แวร์เท่านั้น แนวทางลำดับการตรวจที่ครบถ้วนกว่านี้อยู่ในบทความเรื่องการตรวจสอบหมายเลขบัตรเครดิตในโค้ด
ก้าวต่อไป
เริ่มจากการเขียนชุดทดสอบเล็ก ๆ ที่ครอบคลุมอย่างน้อยสามกรณี คือหมายเลขที่ควรผ่าน หมายเลขที่ถูกสลับหลัก และหมายเลขที่ยาวเกินหรือสั้นเกินช่วงที่รองรับ จากนั้นจึงทดลองกับข้อมูลจริงในรูปแบบของหมายเลขสมมติ ผู้ที่เพิ่งเริ่มต้นอ่านเรื่องนี้เป็นครั้งแรกอาจอยากเริ่มจากบทความหมายเลขบัตรเครดิตสำหรับทดสอบก่อน เพื่อทำความเข้าใจว่าตัวเลขเหล่านี้มีไว้เพื่ออะไร และมีเส้นแบ่งใดที่ต้องระวัง