Skip to content

Instantly share code, notes, and snippets.

@littleli
Last active July 20, 2021 11:49
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save littleli/9cf457a05fd925060d1e4a874834ad5e to your computer and use it in GitHub Desktop.
Save littleli/9cf457a05fd925060d1e4a874834ad5e to your computer and use it in GitHub Desktop.
The implementation of Paillier cryptosystem for Clojure and Babashka
(ns fun.clojure.paillier
(:import [java.math BigInteger]
[java.security SecureRandom]
[java.nio.charset StandardCharsets]))
(defn- random-number! [end]
(let [start (BigInteger/valueOf 2)
interval (.subtract end start)
i (BigInteger. (.bitCount interval) (SecureRandom.))]
(.add start i)))
(defn- L [a n]
(-> a
(.subtract BigInteger/ONE)
(.divide n)))
(defn- square [n]
(.multiply n n))
(defn public-key [n g]
{:n n
:g g})
(defn private-key [lambda mu p q public-key]
{:lambda lambda
:mu mu
:p p
:q q
:public-key public-key})
(defn- get-prime! [bits certainty]
(BigInteger. (/ bits 2) certainty (SecureRandom.)))
(defn key-pair! [bits certainty]
(let [p (get-prime! bits certainty)
q (get-prime! bits certainty)
n (.multiply p q)
g (.add n BigInteger/ONE)
l1 (.subtract p BigInteger/ONE)
l2 (.subtract q BigInteger/ONE)
lambda (.multiply l1 l2)
mu (.modInverse lambda n)
pk (public-key n g)]
{:public-key pk
:private-key (private-key lambda mu p q pk)}))
(defn encrypt! [public-key plaintext]
(let [{:keys [n g]} public-key
nsqr (square n)]
(-> g
(.modPow plaintext nsqr)
(.multiply (.modPow (random-number! n) n nsqr))
(.mod nsqr))))
(defn encrypt-number! [public-key n]
(encrypt! public-key (BigInteger/valueOf n)))
(defn encrypt-string! [public-key str]
(let [bytes (.getBytes str StandardCharsets/UTF_8)]
(encrypt! public-key (BigInteger. bytes))))
(defn h+ [public-key ciphertext1 ciphertext2]
(let [n (:n public-key)]
(-> ciphertext1
(.multiply ciphertext2)
(.mod (square n)))))
(defn h* [public-key ciphertext k]
(let [n (:n public-key)]
(-> ciphertext
(.modPow (BigInteger/valueOf k) (square n)))))
(defn decrypt [private-key ciphertext]
(let [public-key (:public-key private-key)
lambda (:lambda private-key)
n (:n public-key)
nsqr (square n)
mu (:mu private-key)]
(-> (L (.modPow ciphertext lambda nsqr) n)
(.multiply mu)
(.mod n))))
(defn decrypt-string [private-key ciphertext]
(String. (.toByteArray (decrypt private-key ciphertext))
StandardCharsets/UTF_8))
(comment
(def a-pair (key-pair! 1024 8))
(println (:public-key a-pair))
(println)
(println (:private-key a-pair))
(def e (encrypt-number! (:public-key a-pair) 10))
(println)
(println e)
(println (decrypt (:private-key a-pair) e))
(def f (h+ (:public-key a-pair)
(encrypt-number! (:public-key a-pair) 10)
e))
(println (decrypt (:private-key a-pair) f))
(def g (h* (:public-key a-pair) e 10))
(println g)
(println (decrypt (:private-key a-pair) g))
(def secret-name (encrypt-string! (:public-key a-pair) "John Doe"))
(println "secret name: " secret-name)
(println (decrypt-string (:private-key a-pair) secret-name)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment