// modified from http://www.csee.umbc.edu/~kunliu1/research/Paillier.java package threshold.mr04; /** * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ import java.io.Serializable; import java.math.BigInteger; import java.security.SecureRandom; /** * Paillier Cryptosystem <br><br> * References: <br> * [1] Pascal Paillier, "Public-Key Cryptosystems Based on Composite Degree Residuosity Classes," EUROCRYPT'99. * URL: <a href="http://www.gemplus.com/smart/rd/publications/pdf/Pai99pai.pdf">http://www.gemplus.com/smart/rd/publications/pdf/Pai99pai.pdf</a><br> * * [2] Paillier cryptosystem from Wikipedia. * URL: <a href="http://en.wikipedia.org/wiki/Paillier_cryptosystem">http://en.wikipedia.org/wiki/Paillier_cryptosystem</a> * @author Kun Liu (kunliu1@cs.umbc.edu) * @version 1.0 */ public class Paillier implements Serializable { /** * p and q are two large primes. * lambda = lcm(p-1, q-1) = (p-1)*(q-1)/gcd(p-1, q-1). */ private BigInteger p, q, lambda; /** * n = p*q, where p and q are two large primes. */ public BigInteger n; /** * nsquare = n*n */ public BigInteger nSquared; /** * a random integer in Z*_{n^2} where gcd (L(g^lambda mod n^2), n) = 1. */ public BigInteger g; /** * number of bits of modulus */ private int bitLength; private SecureRandom rand = new SecureRandom(); /** * Constructs an instance of the Paillier cryptosystem. * @param bitLengthVal number of bits of modulus * @param certainty The probability that the new BigInteger represents a prime number will exceed (1 - 2^(-certainty)). The execution time of this constructor is proportional to the value of this parameter. */ public Paillier(int bitLengthVal, int certainty) { generateKey(bitLengthVal, certainty); } /** * Sets up the public key and private key. * @param bitLengthVal number of bits of modulus. * @param certainty The probability that the new BigInteger represents a prime number will exceed (1 - 2^(-certainty)). The execution time of this constructor is proportional to the value of this parameter. */ public void generateKey(int bitLengthVal, int certainty) { bitLength = bitLengthVal; /*Constructs two randomly generated positive BigIntegers that are probably prime, with the specified bitLength and certainty.*/ p = new BigInteger(bitLength / 2, certainty, rand); q = new BigInteger(bitLength / 2, certainty, rand); n = p.multiply(q); nSquared = n.multiply(n); g = new BigInteger("2"); lambda = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE)).divide( p.subtract(BigInteger.ONE).gcd(q.subtract(BigInteger.ONE))); /* check whether g is good.*/ if (g.modPow(lambda, nSquared).subtract(BigInteger.ONE).divide(n).gcd(n).intValue() != 1) { System.out.println("g is not good. Choose g again."); System.exit(1); } } public BigInteger encrypt(BigInteger message, PaillierPublicKey pubKey) { BigInteger r = new BigInteger(bitLength, rand); return encrypt(message, pubKey, r); } public static BigInteger encrypt(BigInteger message, PaillierPublicKey pubKey, BigInteger r) { BigInteger g = pubKey.g; BigInteger n = pubKey.N; BigInteger nSquared = n.pow(2); return g.modPow(message, nSquared).multiply(r.modPow(n, nSquared)).mod(nSquared); } /** * Decrypts ciphertext c. plaintext m = L(c^lambda mod n^2) * u mod n, where u = (L(g^lambda mod n^2))^(-1) mod n. * @param c ciphertext as a BigInteger * @return plaintext as a BigInteger */ public BigInteger decrypt(BigInteger c) { BigInteger u = g.modPow(lambda, nSquared).subtract(BigInteger.ONE).divide(n).modInverse(n); return c.modPow(lambda, nSquared).subtract(BigInteger.ONE).divide(n).multiply(u).mod(n); } }