1use std::borrow::Borrow;
2
3pub fn compute_luhn_10_check_digit(code: &str) -> u32 {
4 let mut code_with_check_digit = code.to_owned();
5 code_with_check_digit.push_str("0");
6 let sum: u32 = luhn_10_sum(code_with_check_digit.borrow());
7 return (sum * 9) % 10;
8}
9
10pub fn validate_luhn_10(code: &str) -> bool {
11 let sum: u32 = luhn_10_sum(code);
12 return (sum % 10) == 0;
13}
14
15fn luhn_10_sum(code: &str) -> u32 {
17 let mut sum: u32 = 0;
18 let mut is_odd = (code.chars().count() % 2) != 0;
19 for char in code.chars() {
20 if is_odd {
21 sum += char.to_digit(36).unwrap()
22 } else {
23 let digit = char.to_digit(36).unwrap() * 2;
24 sum += if digit > 9 { digit - 9 } else { digit }
25 }
26 is_odd = !is_odd;
27 }
28 return sum;
29}
30
31
32const VERHOEFF_DIHEDRAL:[[u8; 10]; 10] = [
33 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
34 [1, 2, 3, 4, 0, 6, 7, 8, 9, 5],
35 [2, 3, 4, 0, 1, 7, 8, 9, 5, 6],
36 [3, 4, 0, 1, 2, 8, 9, 5, 6, 7],
37 [4, 0, 1, 2, 3, 9, 5, 6, 7, 8],
38 [5, 9, 8, 7, 6, 0, 4, 3, 2, 1],
39 [6, 5, 9, 8, 7, 1, 0, 4, 3, 2],
40 [7, 6, 5, 9, 8, 2, 1, 0, 4, 3],
41 [8, 7, 6, 5, 9, 3, 2, 1, 0, 4],
42 [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]];
43
44const VERHOEFF_PERMUTATION:[[u8; 10]; 8] = [
45 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
46 [1, 5, 7, 6, 2, 8, 3, 0, 9, 4],
47 [5, 8, 0, 3, 7, 9, 6, 1, 4, 2],
48 [8, 9, 1, 6, 0, 4, 3, 5, 2, 7],
49 [9, 4, 5, 3, 1, 2, 6, 8, 7, 0],
50 [4, 2, 8, 6, 5, 7, 3, 9, 0, 1],
51 [2, 7, 9, 3, 8, 0, 6, 4, 1, 5],
52 [7, 0, 4, 6, 9, 1, 3, 2, 5, 8]];
53
54const VERHOEFF_INV:[u8; 10] = [0, 4, 3, 2, 1, 5, 6, 7, 8, 9];
55
56pub fn validate_verhoeff(code: &str) -> bool {
57 let c = verhoeff_check_digit(code);
58 return c == 0;
59}
60
61pub fn compute_verhoeff_check_digit(code: &str) -> u32 {
62 let mut owned_code = String::from(code);
63 owned_code.push_str("0");
64 let c: usize = verhoeff_check_digit(owned_code.borrow());
65 return VERHOEFF_INV[c] as u32;
66}
67
68fn verhoeff_check_digit(code: &str) -> usize {
70 let mut c: usize = 0;
71 for (idx, char) in code.chars().rev().into_iter().enumerate() {
72 let digit: usize = char.to_digit(36).unwrap() as usize;
73 let p = VERHOEFF_PERMUTATION[idx % 8][digit] as usize;
74 c = VERHOEFF_DIHEDRAL[c][p] as usize;
75 }
76 return c;
77}
78
79#[cfg(test)]
80mod tests {
81 use crate::validator::algorithms::{compute_luhn_10_check_digit, validate_luhn_10, validate_verhoeff, compute_verhoeff_check_digit};
82
83 #[test]
84 fn luhn_validation_algorithm() {
85 assert_eq!(3, compute_luhn_10_check_digit("7992739871"));
86 assert!(validate_luhn_10("79927398713"));
87 assert!(validate_luhn_10("1983081246783"));
88 }
89
90 #[test]
91 fn verhoeff_validation_algorithm() {
92 assert_eq!(3, compute_verhoeff_check_digit("236"));
93 assert!(validate_verhoeff("2363"));
94 assert_eq!(validate_verhoeff("5971654782313"), false);
95 }
96}