Skip to content

Commit

Permalink
Add ISO 7064 Mod 97, 10 algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
kupolak committed Jan 27, 2024
1 parent 7f4e7b6 commit 76d1b57
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/iso7064/dune
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(library
(name iso7064)
(modules mod_37_2)
(modules mod_37_2 mod_97_10)
(libraries tools))
27 changes: 27 additions & 0 deletions lib/iso7064/mod_97_10.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
exception Invalid_format
exception Invalid_checksum

let to_base10 number =
let res = ref "" in
String.iter
(fun x -> res := !res ^ string_of_int (int_of_char x - int_of_char '0'))
number;
!res

let checksum number = int_of_string (to_base10 number) mod 97

let calc_check_digits number =
Printf.sprintf "%02d" (98 - checksum (number ^ "00"))

let validate number =
try
let valid = checksum number = 1 in
if not valid then raise Invalid_checksum;
number
with _ -> raise Invalid_format

let is_valid number =
try
ignore (validate number);
true
with Invalid_format | Invalid_checksum -> false
27 changes: 27 additions & 0 deletions lib/iso7064/mod_97_10.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
(*
The ISO 7064 Mod 97, 10 algorithm.
The Mod 97, 10 algorithm evaluates the whole number as an integer which is
valid if the number modulo 97 is 1. As such it has two check digits.
*)

(* Exception raised when the checksum is invalid *)
exception Invalid_checksum

(* Exception raised when the format is invalid *)
exception Invalid_format

(* Convert a base36 number to base10 *)
val to_base10 : string -> string

(* Calculate the checksum of a number *)
val checksum : string -> int

(* Calculate the extra digits that should be appended to the number to make it a valid number *)
val calc_check_digits : string -> string

(* Check whether the check digit is valid *)
val validate : string -> string

(* Check whether the number is valid *)
val is_valid : string -> bool
5 changes: 5 additions & 0 deletions test/iso7064/dune
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@
(name test_mod_37_2)
(libraries alcotest iso7064)
(modules test_mod_37_2))

(test
(name test_mod_97_10)
(libraries alcotest iso7064)
(modules test_mod_97_10))
32 changes: 32 additions & 0 deletions test/iso7064/test_mod_97_10.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
let test_to_base10 () =
let result = Iso7064.Mod_97_10.to_base10 "16122348495643231" in
Alcotest.(check string) "to_base10" "16122348495643231" result

let test_checksum () =
let result = Iso7064.Mod_97_10.checksum "16122348495643231" in
Alcotest.(check int) "checksum" 31 result

let test_calc_check_digits () =
let result = Iso7064.Mod_97_10.calc_check_digits "4354111611551114" in
Alcotest.(check string) "calc_check_digits" "31" result

let test_validate () =
let result = Iso7064.Mod_97_10.validate "71616009861" in
Alcotest.(check string) "validate" "71616009861" result

let test_is_valid () =
let result = Iso7064.Mod_97_10.is_valid "030633417226" in
Alcotest.(check bool) "is_valid" true result;
let result = Iso7064.Mod_97_10.is_valid "G123489654321Z" in
Alcotest.(check bool) "is_valid" false result

let suite =
[
("test_to_base10", `Quick, test_to_base10)
; ("test_checksum", `Quick, test_checksum)
; ("test_calc_check_digits", `Quick, test_calc_check_digits)
; ("test_validate", `Quick, test_validate)
; ("test_is_valid", `Quick, test_is_valid)
]

let () = Alcotest.run "Mod_37_2" [ ("suite", suite) ]

0 comments on commit 76d1b57

Please sign in to comment.