Last active
July 20, 2021 11:49
-
-
Save littleli/9cf457a05fd925060d1e4a874834ad5e to your computer and use it in GitHub Desktop.
The implementation of Paillier cryptosystem for Clojure and Babashka
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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