From 359286696fd218edc2c0e6912400b04cf6fa70bc Mon Sep 17 00:00:00 2001 From: Athish Pranav D Date: Thu, 22 Aug 2024 18:57:24 +0530 Subject: [PATCH 1/3] Add Paillier enc code Signed-off-by: Athish Pranav D --- pk/common.ml | 6 +++++ pk/paillier.ml | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ pk/rsa.ml | 6 ----- 3 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 pk/paillier.ml diff --git a/pk/common.ml b/pk/common.ml index 01ad98b2..eac7fe67 100644 --- a/pk/common.ml +++ b/pk/common.ml @@ -2,4 +2,10 @@ let rec until p f = let r = f () in if p r then r else until p f let guard p err = if p then Ok () else Error err +let valid_prime name p = + guard Z.(p > zero && is_odd p && Z_extra.pseudoprime p) + (`Msg ("invalid prime " ^ name)) + +let rprime a b = Z.(gcd a b = one) + let ( let* ) = Result.bind diff --git a/pk/paillier.ml b/pk/paillier.ml new file mode 100644 index 00000000..90f93583 --- /dev/null +++ b/pk/paillier.ml @@ -0,0 +1,60 @@ +open Mirage_crypto.Uncommon +open Common + +type pub = { g : Z.t ; n : Z.t ; n2: Z.t} + +type priv = {g:Z.t; n:Z.t ; n2:Z.t ; p: Z.t ; q: Z.t ; lambda: Z.t ; mu: Z.t } + +let two = Z.(~$2) + +let minimum_octets = 12 +let minimum_bits = 8 * minimum_octets - 7 + +let pub ~g ~n = + let n2 = Z.(mul n n) in + let* () = guard ( g < n2 ) ( `Msg "g is greater than n^2" ) in + let* () = guard Z.( n > zero && numbits n >= minimum_bits) ( `Msg "invalid nZ" ) in + Ok {g; n; n2} + +let priv ~p ~q = + let* () = valid_prime "p" p in + let* () = valid_prime "q" q in + let* () = guard (p <> q) (`Msg "p and q are the same number") in + let* () = guard Z.((lcm (mul p q) (mul (pred p) (pred q)))=one) (`Msg "gcd(p.q, (p−1).(q−1)) = 1") in + let n = Z.(mul p q) in + let g = Z.(succ n) in + let n2 = Z.(mul n n) in + let lambda = Z.(lcm (pred p) (pred q)) in + let mu = Z.(invert lambda n) in + let _ = pub ~g ~n in + Ok {g; n; n2; p; q; lambda; mu} + +let pub_of_priv ({g; n; n2; _}: priv) = {g; n; n2} + +let pub_bits ({ n; _ } : pub) = Z.numbits n +and priv_bits ({ n; _ } : priv) = Z.numbits n + +let random_bigint_range ~lower ~upper = + let diff = Z.sub upper lower in + Z.(add lower (Random.State.bits (Random.get_state ()) |> of_int) |> rem diff) + +let rec generate ?g ~bits ()= + if bits < minimum_bits then + invalid_arg "Paillier.generate: bits: %d < minimum_bits: %d" bits minimum_bits; + let (pb, qb) = (bits / 2, bits - bits / 2) in + let (p, q) = Z_extra.(prime ?g ~msb:2 pb, prime ?g ~msb:2 qb) in + match priv ~p ~q with + | Error _ -> generate ?g ~bits () + | Ok priv_key -> pub_of_priv priv_key, priv_key + +let encrypt ~(pub_key : pub) ~msg ?(r=random_bigint_range ~lower:Z.one ~upper:Z.(pred pub_key.n)) () = + if msg < Z.zero then + invalid_arg "Paillier.encrypt: msg must be non-negative"; + let gm = Z.powm pub_key.g msg pub_key.n2 in + let rn = Z.powm r pub_key.n pub_key.n2 in + Z.(rem (mul gm rn) pub_key.n2) + +let decrypt ~(priv_key : priv) ~c = + let cn = Z.powm c priv_key.lambda priv_key.n2 in + let lx = Z.(div (sub cn one) priv_key.n) in + Z.(rem (mul priv_key.mu lx) priv_key.n) diff --git a/pk/rsa.ml b/pk/rsa.ml index 25edf933..27fd43fa 100644 --- a/pk/rsa.ml +++ b/pk/rsa.ml @@ -53,12 +53,6 @@ type priv = { p : Z.t ; q : Z.t ; dp : Z.t ; dq : Z.t ; q' : Z.t } -let valid_prime name p = - guard Z.(p > zero && is_odd p && Z_extra.pseudoprime p) - (`Msg ("invalid prime " ^ name)) - -let rprime a b = Z.(gcd a b = one) - let valid_e ~e ~p ~q = let* () = guard (rprime e (Z.pred p) && rprime e (Z.pred q)) From 0dfb98d1f046c2323f7d5aa1cc990a547a29ecc2 Mon Sep 17 00:00:00 2001 From: Athish Pranav D Date: Thu, 22 Aug 2024 19:50:49 +0530 Subject: [PATCH 2/3] Add Interface Signed-off-by: Athish Pranav D --- pk/mirage_crypto_pk.ml | 1 + pk/mirage_crypto_pk.mli | 52 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/pk/mirage_crypto_pk.ml b/pk/mirage_crypto_pk.ml index 963a5f29..5a121cdf 100644 --- a/pk/mirage_crypto_pk.ml +++ b/pk/mirage_crypto_pk.ml @@ -2,3 +2,4 @@ module Dh = Dh module Dsa = Dsa module Rsa = Rsa module Z_extra = Z_extra +module Paillier = Paillier \ No newline at end of file diff --git a/pk/mirage_crypto_pk.mli b/pk/mirage_crypto_pk.mli index 832b4aa4..f8bd4eda 100644 --- a/pk/mirage_crypto_pk.mli +++ b/pk/mirage_crypto_pk.mli @@ -518,3 +518,55 @@ module Z_extra : sig (** [gen_r ~g low high] picks a value from the interval [\[low, high - 1\]] uniformly at random. *) end + +(** {b Paillier Encryption algorith} Paillier Encryption algorith. *) +module Paillier : sig + + (** {1 Paillier Encryption algorithm} *) + + type priv = private { + g : Z.t ; (** Generator *) + n : Z.t ; (** Modulus *) + n2 : Z.t ; (** Modulus squared *) + p : Z.t ; (** First prime *) + q : Z.t ; (** Second prime *) + lambda : Z.t ; (** Carmichael's totient function *) + mu : Z.t ; (** Inverse of totient function *) + } + + val priv : p:Z.t -> q:Z.t -> (priv, [> `Msg of string ]) result + (** [priv ~p ~q] constructs a private Paillier keys from the given + numbers. Will result in an error if parameters are ill-formed: same as + {!val-pub}. *) + + type pub = private { + g : Z.t ; (** Generator *) + n : Z.t ; (** Modulus *) + n2 : Z.t ; (** Modulus squared *) + } + (** Public key, a subset of {{!type-priv}private key}. *) + + val pub : g:Z.t -> n:Z.t -> (pub, [> `Msg of string ]) result + (** [pub ~g ~n] constructs a public Paillier key from the given + numbers. Will result in an error if the parameters are not well-formed. *) + + val pub_of_priv : priv -> pub + (** Extract the public component from a private key. *) + + val pub_bits : pub -> int + (** [pub_bits ~pub] returns the number of bits in the public key *) + + val priv_bits : priv -> int + (** [priv_bits ~priv] returns the number of bits in the private key *) + + val generate : ?g:Mirage_crypto_rng.g -> bits:int -> unit -> pub*priv + (** [generate g bits] is a fresh {{!type-priv}private} key. *) + + val encrypt : pub_key:pub -> msg:Z.t -> ?r:Z.t -> unit -> Z.t + (** [encrypt msg pub ~r ()] encrypts the message [msg] using the public key + [r] is a random value used to ensure that the encryption is unpredictable. + @raise Invalid_argument if [msg] is negative. *) + + val decrypt : priv_key:priv -> c:Z.t -> Z.t + (** [decrypt ciphertext priv] decrypts the ciphertext using the private key. *) +end From 8a72db8a4c6116373d75c744040771028eabc7fc Mon Sep 17 00:00:00 2001 From: Athish Pranav D Date: Thu, 22 Aug 2024 20:26:41 +0530 Subject: [PATCH 3/3] Add tests Signed-off-by: Athish Pranav D --- tests/dune | 2 +- tests/test_paillier.ml | 62 +++++++++++++++++++++++++++++++++++++++++ tests/test_pk_runner.ml | 1 + 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 tests/test_paillier.ml diff --git a/tests/dune b/tests/dune index 32afebe7..4c09efe4 100644 --- a/tests/dune +++ b/tests/dune @@ -22,7 +22,7 @@ (libraries test_common mirage-crypto-pk mirage-crypto-rng.unix randomconv ounit2) (package mirage-crypto-pk) - (modules test_numeric test_dh test_dsa test_rsa test_pk_runner)) + (modules test_numeric test_dh test_dsa test_rsa test_paillier test_pk_runner)) (test (name test_entropy_collection) diff --git a/tests/test_paillier.ml b/tests/test_paillier.ml new file mode 100644 index 00000000..261cc632 --- /dev/null +++ b/tests/test_paillier.ml @@ -0,0 +1,62 @@ +open OUnit2 + +(* open Mirage_crypto.Uncommon *) +open Mirage_crypto_pk + +open Test_common + +let vz = Z.of_string_base 16 + +module Null = struct + + type g = string ref + + let block = 1 + + let create ?time:_ () = ref "" + + let generate_into ~g buf ~off n = + try + Bytes.blit_string !g 0 buf off n; + g := String.sub !g n (String.length !g - n) + with Invalid_argument _ -> raise Mirage_crypto_rng.Unseeded_generator + + let reseed ~g buf = g := !g ^ buf + + let seeded ~g = String.length !g > 0 + + let accumulate ~g _source = `Acc (reseed ~g) + + let pools = 0 +end + +let random_is seed = + Mirage_crypto_rng.create ~seed:seed (module Null) + +let gen_paillier ~bits = + let key = Paillier.(generate ~bits ()) in + assert_equal + ~msg:Printf.(sprintf "key size not %d bits" bits) + bits Paillier.(priv_bits (snd key)) ; + key + +let paillier_selftest ~bits n = + "selftest" >:: times ~n @@ fun _ -> + let msg = Z.(~$100) in + let key = gen_paillier ~bits in + let enc = Paillier.(encrypt ~pub_key:(fst key) ~msg ()) in + let dec = Paillier.(decrypt ~priv_key:(snd key) ~c:enc) in + + assert_equal + ~msg:Printf.(sprintf "failed decryption with") + msg dec + + +let suite = [ + "Paillier" >::: [ + paillier_selftest ~bits:89 100 ; + paillier_selftest ~bits:131 100 ; + paillier_selftest ~bits:1024 10 ; + paillier_selftest ~bits:2048 10 ; + ] ; +] diff --git a/tests/test_pk_runner.ml b/tests/test_pk_runner.ml index ae47e676..797e5845 100644 --- a/tests/test_pk_runner.ml +++ b/tests/test_pk_runner.ml @@ -6,6 +6,7 @@ let suite = "DHE" >::: Test_dh.suite; "DSA" >::: Test_dsa.suite; "RSA" >::: Test_rsa.suite; + "Paillier" >::: Test_paillier.suite; ] let () =