From 9f21f4b97a8f1396e2da4eaa51475cec061f1ae9 Mon Sep 17 00:00:00 2001 From: Guillaume Huysmans Date: Sat, 24 Aug 2019 00:41:25 +0200 Subject: [PATCH] Implemented the Chinese Remainder Theorem --- bin/chinese.ml | 25 +++++++++++++++++++++++++ bin/dune | 4 ++-- lib/numbers.ml | 7 +++++++ lib/numbers.mli | 3 +++ 4 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 bin/chinese.ml diff --git a/bin/chinese.ml b/bin/chinese.ml new file mode 100644 index 0000000..c6b0741 --- /dev/null +++ b/bin/chinese.ml @@ -0,0 +1,25 @@ +open Toy_crypto +module M = Numbers.Make (Int) (* FIXME *) + +open Printf + + +let () = + let int_arg n = int_of_string Sys.argv.(n) in + if Array.length Sys.argv = 5 then + let a, p, b, q = int_arg 1, int_arg 2, int_arg 3, int_arg 4 in + printf "Input problem:\n\tx = %d mod %d\n\tx = %d mod %d\n" a p b q; + try + let n = M.crt (a, p) (b, q) in + printf "Solution:\n\tx = %d mod %d\n" n (p * q) + with Failure _ -> + printf "No solution:\n\t%d and %d aren't coprime.\n" p q + else + let p, q = int_arg 1, int_arg 2 in + printf "(a, b) represents this:\n\tx = a mod %d\n\tx = b mod %d\n" p q; + for a=0 to p-1 do + for b=0 to q-1 do + let n = M.crt (a, p) (b, q) in + printf "(%d, %d) -> %d\n" a b n + done + done diff --git a/bin/dune b/bin/dune index 695d4cf..afa6f09 100644 --- a/bin/dune +++ b/bin/dune @@ -1,5 +1,5 @@ -(executable - (name main) +(executables + (names main chinese) (libraries toy_crypto)) (install (section bin) diff --git a/lib/numbers.ml b/lib/numbers.ml index e07f4d3..e9b9392 100644 --- a/lib/numbers.ml +++ b/lib/numbers.ml @@ -28,6 +28,7 @@ module type S = sig val euclid: N.t -> N.t -> e val gcd: N.t -> N.t -> N.t val inv: N.t -> m:N.t -> N.t + val crt: N.t * N.t -> N.t * N.t -> N.t val random: bits:int -> N.t val random_prime: bits:int -> N.t val of_string : string -> N.t @@ -102,6 +103,12 @@ module Make (N: Concrete) = struct (* this should not happen *) failwith "non-invertible value" + let crt (a, p) (b, q) = + let open N in + let p1, q1 = inv p ~m:q, inv q ~m:p in + let n = (a * q1 * q + b * p1 * p) mod (p * q) in + if n < zero then n + p * q else n + let random ~bits = let rec f a = function | 0 -> a diff --git a/lib/numbers.mli b/lib/numbers.mli index d3f54ba..d6dd188 100644 --- a/lib/numbers.mli +++ b/lib/numbers.mli @@ -30,6 +30,9 @@ module type S = sig val gcd: N.t -> N.t -> N.t val inv: N.t -> m:N.t -> N.t + val crt: N.t * N.t -> N.t * N.t -> N.t + (* [crt (a, p) (b, q)] solves ${x = a mod p, x = b mod q}$ *) + val random: bits:int -> N.t val random_prime: bits:int -> N.t val of_string : string -> N.t