pub fn checksum(arr: &[usize], dict_len: usize) -> usize {
let (sum, _) = arr.iter().rev().fold((0usize, 2usize), |(sum, factor), digit| {
let mut addend = factor * *digit;
let factor = factor ^ 3; addend = (addend / dict_len) + addend % dict_len;
(sum + addend, factor)
});
(dict_len - (sum % dict_len)) % dict_len
}
pub fn is_valid(arr: &[usize], dict_len: usize) -> bool {
if arr.len() < 2 {
return false;
}
let cs = checksum(&arr[..arr.len() - 1], dict_len);
cs == arr[arr.len() - 1]
}
#[cfg(test)]
mod test {
use crate::util::luhn::*;
#[test]
fn luhn_6() {
assert_eq!(checksum(&[0, 1, 2, 3, 4, 5], 6), 4);
for i in 0..6 {
let valid = is_valid(&[0, 1, 2, 3, 4, 5, i], 6);
match i {
4 => assert!(valid),
_ => assert_eq!(valid, false),
}
}
}
#[test]
fn luhn_10() {
assert_eq!(checksum(&[7, 9, 9, 2, 7, 3, 9, 8, 7, 1], 10), 3);
for i in 0..10 {
let valid = is_valid(&[7, 9, 9, 2, 7, 3, 9, 8, 7, 1, i], 10);
match i {
3 => assert!(valid),
_ => assert_eq!(valid, false),
}
}
assert_eq!(checksum(&[1, 0, 4], 10), 0);
assert_eq!(checksum(&[9, 1, 2, 4, 3, 4, 3, 3, 0], 10), 3);
assert!(is_valid(&[9, 1, 2, 4, 3, 4, 3, 3, 0, 3], 10));
assert!(is_valid(&[0, 1, 2, 4, 3, 4, 3, 3, 9, 3], 10));
}
}