├── BGN.java ├── Benaloh.java ├── LICENSE ├── Paillier.java └── README.md /BGN.java: -------------------------------------------------------------------------------- 1 | package BGN; 2 | import java.math.BigInteger; 3 | /* 4 | * This source code uses the JPBC (Java Pairing-Based 5 | * Cryptography) library, 6 | * which can be downloaded from 7 | * http://gas.dia.unisa.it/projects/jpbc/ 8 | */ 9 | import it.unisa.dia.gas.jpbc.*; 10 | import it.unisa.dia.gas.plaf.jpbc.pairing.PairingFactory; 11 | import it.unisa.dia.gas.plaf.jpbc.pairing.a1.TypeA1CurveGenerator; 12 | /** 13 | * @ClassName: BGN 14 | * @Description: This is a sample java source code of BGN PKE. 15 | */ 16 | public class BGN { 17 | /** 18 | * @ClassName: PublicKey 19 | * @Description: This is a class for storing the 20 | * public key (n,G,GT,e,g,h) of BGN PKE. 21 | */ 22 | public class PublicKey { 23 | private BigInteger n; 24 | private Field Field_G, Field_GT; 25 | private Pairing pairing; 26 | private Element g, h; 27 | public PublicKey(BigInteger n, Field G, Field GT, Pairing pairing, Element g, 28 | Element h) { 29 | this.n = n; 30 | this.Field_G = G; 31 | this.Field_GT = GT; 32 | this.pairing = pairing; 33 | this.g = g; 34 | this.h = h; 35 | } 36 | public Element getG() { 37 | return g; 38 | } 39 | public Element getH() { 40 | return h; 41 | } 42 | public BigInteger getN() { 43 | return n; 44 | } 45 | public Pairing getPairing() { 46 | return pairing; 47 | } 48 | public Field getField_G() { 49 | return Field_G; 50 | } 51 | public Field getField_GT() { 52 | return Field_GT; 53 | } 54 | } 55 | /** 56 | * @ClassName: PrivateKey 57 | * @Description: This is a class for storing the 58 | * private key (p) of BGN PKE. 59 | */ 60 | public class PrivateKey { 61 | private BigInteger p; 62 | public PrivateKey(BigInteger p) { 63 | this.p = p; 64 | } 65 | public BigInteger getP() { 66 | return p; 67 | } 68 | } 69 | private static final int T = 100; // The max range of message m 70 | private PublicKey pubkey; 71 | private PrivateKey prikey; 72 | /** 73 | * @Title: keyGeneration 74 | * @Description: This function is responsible for 75 | * generating the public keys and the private keys. 76 | * @param k 77 | * the security parameter, which decides the 78 | * length of two large prime (p and q). 79 | * @return void 80 | */ 81 | public void keyGeneration(int k) { 82 | TypeA1CurveGenerator pg = new 83 | TypeA1CurveGenerator(2, k); 84 | PairingParameters pp = pg.generate(); 85 | Pairing pairing = PairingFactory.getPairing(pp); 86 | BigInteger n = pp.getBigInteger("n"); 87 | BigInteger q = pp.getBigInteger("n0"); 88 | BigInteger p = pp.getBigInteger("n1"); 89 | Field Field_G = pairing.getG1(); 90 | Field Field_GT = pairing.getGT(); 91 | Element g = Field_G.newRandomElement().getImmutable(); 92 | Element h = g.pow(q).getImmutable(); 93 | pubkey = new PublicKey(n, Field_G, Field_GT, 94 | pairing, g, h); 95 | prikey = new PrivateKey(p); 96 | } 97 | /** 98 | * @Title: getPubkey 99 | * @Description: This function returns the public key of 100 | * BGN PKE. 101 | * @return PublicKey The public key used to encrypt 102 | * the data. 103 | */ 104 | public PublicKey getPubkey() { 105 | return pubkey; 106 | } 107 | /** 108 | * @Title: getPrikey 109 | * @Description: This function returns the private key of 110 | * BGN PKE. 111 | * @return PrivateKey The private key used to decrypt 112 | * the data. 113 | */ 114 | public PrivateKey getPrikey() { 115 | return prikey; 116 | } 117 | /** 118 | * @Title: encrypt 119 | * @Description: This function is to encrypt the message 120 | * m, m in [0,1,2,...,T], 121 | * T=100 with public key. 122 | * @param m 123 | * The message 124 | * @param pubkey 125 | * The public key of BGN PKE. 126 | * @return Element The ciphertext. 127 | * @throws Exception 128 | * If the plaintext is not in [0,1,2,...,n], 129 | * there is an exception. 130 | */ 131 | public static Element encrypt(int m, PublicKey pubkey) 132 | throws Exception { 133 | if (m > T) { 134 | throw new Exception( 135 | "BGN.encrypt(int m, PublicKey pubkey): " 136 | + "plaintext m is not in [0,1,2,...," 137 | + T + "]"); 138 | } 139 | Pairing pairing = pubkey.getPairing(); 140 | Element g = pubkey.getG(); 141 | Element h = pubkey.getH(); 142 | BigInteger r = pairing.getZr().newRandomElement() 143 | .toBigInteger(); 144 | return g.pow(BigInteger.valueOf(m)).mul(h.pow(r)) 145 | .getImmutable(); 146 | } 147 | /** 148 | * 149 | * @Title: decrypt 150 | * @Description: This function is to decrypt the ciphertext 151 | * with the public key and the private key. 152 | * @param c 153 | * The ciphertext. 154 | * @param pubkey 155 | * The public key of BGN PKE. 156 | * @param prikey 157 | * The private key of BGN PKE. 158 | * @return int The plaintext. 159 | * @throws Exception 160 | * If the plaintext is not in [0,1,2,...,n], 161 | * there is an exception. 162 | */ 163 | public static int decrypt(Element c, PublicKey pubkey, 164 | PrivateKey prikey) throws Exception { 165 | BigInteger p = prikey.getP(); 166 | Element g = pubkey.getG(); 167 | Element cp = c.pow(p).getImmutable(); 168 | Element gp = g.pow(p).getImmutable(); 169 | for (int i = 0; i <= T; i++) { 170 | if (gp.pow(BigInteger.valueOf(i)).isEqual(cp)) { 171 | return i; 172 | } 173 | } 174 | throw new Exception( 175 | "BGN.decrypt(Element c, PublicKey pubkey, PrivateKey prikey): " 176 | + "plaintext m is not in [0,1,2,...," 177 | + T + "]"); 178 | } 179 | public static int decrypt_mul2(Element c, PublicKey pubkey, 180 | PrivateKey prikey) throws Exception { 181 | BigInteger p = prikey.getP(); 182 | Element g = pubkey.getG(); 183 | Element cp = c.pow(p).getImmutable(); 184 | Element egg = pubkey.getPairing().pairing(g, g).pow(p) 185 | .getImmutable(); 186 | for (int i = 0; i <= T; i++) { 187 | if (egg.pow(BigInteger.valueOf(i)).isEqual(cp)) { 188 | return i; 189 | } 190 | } 191 | throw new Exception( 192 | "BGN.decrypt(Element c, PublicKey pubkey, PrivateKey prikey): " 193 | + "plaintext m is not in [0,1,2,...," 194 | + T + "]"); 195 | } 196 | /** 197 | * @Title: add 198 | * @Description: The function supports the homomorphic 199 | * addition with two ciphertext. 200 | * @param c1 201 | * The ciphertext. 202 | * @param c2 203 | * The ciphertext. 204 | * @parampubkey 205 | * The public key of BGN PKE. 206 | * @return Element The return value is c1*c2. 207 | */ 208 | public static Element add(Element c1, Element c2) { 209 | return c1.mul(c2).getImmutable(); 210 | } 211 | /** 212 | * @Title: mul1 213 | * @Description: The function supports the homomorphic 214 | * multiplication with one ciphertext 215 | * and one plaintext. 216 | * @paramc 217 | * The ciphertext. 218 | * @paramm 219 | * The plaintext. 220 | * @parampubkey 221 | * The public key of BNG PKE. 222 | * @return Element The return value is c^m. 223 | */ 224 | public static Element mul1(Element c1, int m2) { 225 | return c1.pow(BigInteger.valueOf(m2)).getImmutable(); 226 | } 227 | /** 228 | * @Title: mul2 229 | * @Description: TODO 230 | * @param c1 231 | * The ciphertext. 232 | * @param c2 233 | * The ciphertext. 234 | * @param pubkey 235 | * The public key of BNG PKE. 236 | * @return Element The return value is e(c1,c2). 237 | */ 238 | public static Element mul2(Element c1, Element c2, 239 | PublicKey pubkey) { 240 | Pairing pairing = pubkey.getPairing(); 241 | return pairing.pairing(c1, c2).getImmutable(); 242 | } 243 | /** 244 | * @Title: selfBlind 245 | * @Description: The function supports the homomorphic 246 | * self-blinding with one ciphertext 247 | * and one random number. 248 | * @paramc 249 | * The ciphertext. 250 | * @paramr 251 | * A random number in Z_n. 252 | * @param pubkey 253 | * The public key of BNG PKE. 254 | * @return Element The return value is c1*h^r2. 255 | */ 256 | public static Element selfBlind(Element c1, BigInteger r2, 257 | PublicKey pubkey) { 258 | Element h = pubkey.getH(); 259 | return c1.mul(h.pow(r2)).getImmutable(); 260 | } 261 | public static void main(String[] args) { 262 | BGN bgn = new BGN(); 263 | // Key Generation 264 | bgn.keyGeneration(512); 265 | BGN.PublicKey pubkey = bgn.getPubkey(); 266 | BGN.PrivateKey prikey = bgn.getPrikey(); 267 | // Encryption and Decryption 268 | int m = 5; 269 | Element c = null; 270 | int decrypted_m = 0; 271 | try { 272 | c = BGN.encrypt(m, pubkey); 273 | decrypted_m = BGN.decrypt(c, pubkey, prikey); 274 | } catch (Exception e) { 275 | e.printStackTrace(); 276 | } 277 | if (decrypted_m == m) { 278 | System.out.println("Encryption and Decryption " 279 | + "test successfully."); 280 | } 281 | // Homomorphic Properties 282 | // Addition 283 | int m1 = 5; 284 | int m2 = 6; 285 | try { 286 | Element c1 = BGN.encrypt(m1, pubkey); 287 | Element c2 = BGN.encrypt(m2, pubkey); 288 | Element c1mulc2 = BGN.add(c1, c2); 289 | int decrypted_c1mulc2 = BGN.decrypt(c1mulc2, 290 | pubkey, prikey); 291 | if (decrypted_c1mulc2 == (m1 + m2)) { 292 | System.out.println("Homomorphic addition " 293 | + "tests successfully."); 294 | } 295 | } catch (Exception e) { 296 | e.printStackTrace(); 297 | } 298 | // multiplication-1 299 | m1 = 5; 300 | m2 = 6; 301 | try { 302 | Element c1 = BGN.encrypt(m1, pubkey); 303 | Element c1expm2 = BGN.mul1(c1, m2); 304 | int decrypted_c1expm2 = BGN.decrypt(c1expm2, 305 | pubkey, prikey); 306 | if (decrypted_c1expm2 == (m1 * m2)) { 307 | System.out.println("Homomorphic multiplication-1 " 308 | + "tests successfully."); 309 | } 310 | } catch (Exception e) { 311 | 312 | e.printStackTrace(); 313 | } 314 | // multiplication-2 315 | m1 = 5; 316 | m2 = 6; 317 | try { 318 | Element c1 = BGN.encrypt(m1, pubkey); 319 | Element c2 = BGN.encrypt(m2, pubkey); 320 | Element c1pairingc2 = pubkey.getPairing() 321 | .pairing(c1, c2).getImmutable(); 322 | int decrypted_c1pairingc2 = 323 | BGN.decrypt_mul2(c1pairingc2, pubkey, prikey); 324 | if (decrypted_c1pairingc2 == (m1 * m2)) { 325 | System.out.println("Homomorphic multiplication-2 " 326 | + "tests successfully."); 327 | } 328 | } catch (Exception e) { 329 | e.printStackTrace(); 330 | } 331 | // self-Blinding 332 | m1 = 5; 333 | try { 334 | BigInteger r2 = pubkey.getPairing().getZr() 335 | .newRandomElement().toBigInteger(); 336 | Element c1 = BGN.encrypt(m1, pubkey); 337 | Element c1_selfblind = BGN.selfBlind(c1, 338 | r2, pubkey); 339 | int decrypted_c1_selfblind = 340 | BGN.decrypt(c1_selfblind, pubkey, prikey); 341 | if (decrypted_c1_selfblind == m1) { 342 | System.out.println("Homomorphic self-blinding " 343 | + "tests successfully."); 344 | } 345 | } catch (Exception e) { 346 | e.printStackTrace(); 347 | } 348 | } 349 | } -------------------------------------------------------------------------------- /Benaloh.java: -------------------------------------------------------------------------------- 1 | package Benaloh; 2 | 3 | 4 | import java.math.BigInteger; 5 | import java.security.SecureRandom; 6 | import java.util.Random; 7 | 8 | public class Benaloh { 9 | 10 | // key generation 11 | 12 | public class PublicKey { 13 | private BigInteger n, y; 14 | public PublicKey(BigInteger n, BigInteger y) { 15 | this.n = n; 16 | this.y = y; 17 | } 18 | public BigInteger getN() { 19 | return n; 20 | } 21 | public BigInteger getY() { 22 | return y; 23 | } 24 | } 25 | //private key 26 | 27 | public class PrivateKey { 28 | private BigInteger x, phi; 29 | public PrivateKey(BigInteger phi, BigInteger x) { 30 | this.phi = phi; 31 | this.x = x; 32 | } 33 | public BigInteger getPhi() { 34 | return phi; 35 | } 36 | public BigInteger getX() { 37 | return x; 38 | } 39 | } 40 | 41 | private PublicKey pubkey; 42 | private PrivateKey prikey; 43 | public BigInteger R; 44 | private final int cert=64; 45 | 46 | 47 | public PublicKey getPubkey() { 48 | return pubkey; 49 | } 50 | 51 | public PrivateKey getPrikey(){ 52 | return prikey; 53 | } 54 | 55 | public void keyGeneration(int k){ 56 | 57 | // int r=GenerateR(); 58 | BigInteger p, q, p_minus_one,q_minus_one,R; 59 | R=BigInteger.valueOf(199); 60 | this.R=R; 61 | 62 | do { 63 | p = new BigInteger(k, cert, new SecureRandom()); 64 | p_minus_one=p.subtract(BigInteger.ONE); 65 | }while(p_minus_one.mod(this.R).intValue()!=0 66 | || p_minus_one.divide(R).gcd(R).intValue()!=1); 67 | 68 | do { 69 | q = new BigInteger(k, cert,new SecureRandom()); 70 | q_minus_one=q.subtract(BigInteger.ONE); 71 | } while (p.compareTo(q) == 0 || q_minus_one.gcd(R).intValue()!=1); 72 | 73 | BigInteger n=p.multiply(q); 74 | BigInteger phi=p_minus_one.multiply(q_minus_one); 75 | 76 | // Now we have p and q and r with all conditions 77 | BigInteger y=itemZStarN(n,phi,R); 78 | prikey= new PrivateKey(phi,y.modPow(phi.divide(R),n)); 79 | pubkey=new PublicKey(n,y); 80 | 81 | } 82 | 83 | public BigInteger encrypt(int m){ 84 | BigInteger u=randomZStarN(this.pubkey.getN()); 85 | BigInteger cipher1=pubkey.getY().modPow(BigInteger.valueOf(m),pubkey.getN()); 86 | BigInteger cipher2=u.modPow(this.R,pubkey.getN()); 87 | return cipher1.multiply(cipher2).mod(pubkey.getN()); 88 | } 89 | 90 | public int decrypt(BigInteger cipher){ 91 | BigInteger a= cipher.modPow(this.prikey.getPhi().divide(this.R),this.pubkey.getN()); 92 | 93 | BigInteger c; 94 | for(int i=0;i= 0 || r.gcd(n).intValue() 116 | != 1||r.modPow(phi.divide(R),n).intValue()==1); 117 | return r; 118 | } 119 | public static BigInteger randomZStarN(BigInteger n) { 120 | BigInteger r; 121 | do { 122 | r = new BigInteger(n.bitLength(), new 123 | SecureRandom()); 124 | } while (r.compareTo(n) >= 0 || r.gcd(n).intValue() 125 | != 1); 126 | return r; 127 | } 128 | public BigInteger add(BigInteger c1, BigInteger c2) { 129 | return c1.multiply(c2).mod(this.pubkey.getN()); 130 | } 131 | public BigInteger sub(BigInteger c1, BigInteger c2) { 132 | BigInteger c2_inverse=c2.modInverse(this.pubkey.getN()); 133 | return c1.multiply(c2_inverse).mod(this.pubkey.getN()); 134 | } 135 | public static void main(String[] args) { 136 | Benaloh b=new Benaloh(); 137 | b.keyGeneration(512); 138 | int message=100; 139 | BigInteger c=b.encrypt(message); 140 | int m=b.decrypt(c); 141 | if(m==message) System.out.println("encryption-decryption is ok"); 142 | else System.out.println("no"); 143 | 144 | // Test for homomorphic features 145 | // Test for addition feature E(message1+message2%r)=cipher1.cipher2 146 | int message1=10; 147 | BigInteger cipher1=b.encrypt(message1); 148 | 149 | int message2=20; 150 | BigInteger cipher2=b.encrypt(message2); 151 | 152 | BigInteger result_cipher_add=b.add(cipher1,cipher2); 153 | int result_addition=b.decrypt(result_cipher_add); 154 | if((message1+message2)%b.R.intValue()==result_addition)System.out.println("addition feature is working correctly!"); 155 | // 156 | // Test for Subtraction E(message1-message2%r)=cipher1.(cipher2)^-1 157 | BigInteger result_cipher_sub=b.sub(cipher2,cipher1); 158 | int result_sub=b.decrypt(result_cipher_sub); 159 | if((message2-message1)%b.R.intValue()==result_sub)System.out.println("subtraction feature is working correctly!"); 160 | 161 | } 162 | 163 | } 164 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Nasim Maleki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Paillier.java: -------------------------------------------------------------------------------- 1 | package Paillier; 2 | import java.math.BigInteger; 3 | import java.security.SecureRandom; 4 | /** 5 | * @ClassName: Paillier 6 | * @Description: This is a sample java source code of Paillier 7 | * PKE. 8 | */ 9 | public class Paillier { 10 | /** 11 | * @ClassName: PublicKey 12 | * @Description: This is a class for storing the public 13 | * key (n, g) of Paillier PKE. 14 | */ 15 | public class PublicKey { 16 | private BigInteger n, g; 17 | public PublicKey(BigInteger n, BigInteger g) { 18 | this.n = n; 19 | this.g = g; 20 | } 21 | public BigInteger getN() { 22 | return n; 23 | } 24 | public BigInteger getG() { 25 | return g; 26 | } 27 | } 28 | /** 29 | * @ClassName: PrivateKey 30 | * @Description: This is a class for storing the private 31 | * key (lambda, mu) of Paillier PKE. 32 | */ 33 | public class PrivateKey { 34 | private BigInteger lambda, mu; 35 | public PrivateKey(BigInteger lambda, BigInteger mu) { 36 | this.lambda = lambda; 37 | this.mu = mu; 38 | } 39 | public BigInteger getLambda() { 40 | return lambda; 41 | } 42 | public BigInteger getMu() { 43 | return mu; 44 | } 45 | } 46 | private final int CERTAINTY = 64; 47 | private PublicKey pubkey; // The public key of Paillier PKE, (n, g) 48 | private PrivateKey prikey; // The private key of Paillier PKE, (lambda, mu) 49 | /** 50 | * @Title: getPubkey 51 | * @Description: This function returns the generated 52 | * public key. 53 | * @return PublicKey The public key used to encrypt 54 | * the data. 55 | */ 56 | public PublicKey getPubkey() { 57 | return pubkey; 58 | } 59 | /** 60 | * @Title: getPrikey 61 | * @Description: This function returns the generated 62 | * private key. 63 | * @return PrivateKey The private key used to decrypt 64 | * the data. 65 | */ 66 | public PrivateKey getPrikey() { 67 | return prikey; 68 | } 69 | /** 70 | * @Title: keyGeneration 71 | * @Description: This function is to help generate the 72 | * public key and 73 | * private key for encryption and decryption. 74 | * @param k 75 | * k is the security parameter, which decides 76 | * the length of two large primes (p and q). 77 | * @return void 78 | */ 79 | public void keyGeneration(int k) { 80 | BigInteger p_prime, q_prime, p, q; 81 | do { 82 | p_prime = new BigInteger(k, CERTAINTY, 83 | new SecureRandom()); 84 | p = (p_prime.multiply(BigInteger.valueOf(2))) 85 | .add(BigInteger.ONE); 86 | } while (!p.isProbablePrime(CERTAINTY)); 87 | do { 88 | do { 89 | q_prime = new BigInteger(k, CERTAINTY,new SecureRandom()); 90 | } while (p_prime.compareTo(q_prime) == 0); 91 | q = (q_prime.multiply(BigInteger.valueOf(2))) 92 | .add(BigInteger.ONE); 93 | } while (!q.isProbablePrime(CERTAINTY)); 94 | // The following steps are to generate the keys 95 | // n=p*q 96 | BigInteger n = p.multiply(q); 97 | // nsquare=n^2 98 | BigInteger nsquare = n.pow(2); 99 | // a generator g=(1+n) in Z*_(n^2) 100 | BigInteger g = BigInteger.ONE.add(n); 101 | // lambda = lcm(p-1, q-1) = p_prime*q_prime 102 | BigInteger lambda = BigInteger.valueOf(2) 103 | .multiply(p_prime) 104 | .multiply(q_prime); 105 | // mu = (L(g^lambda mod n^2))^{-1} mod n 106 | BigInteger mu = Lfunction(g.modPow(lambda, nsquare), n) 107 | .modInverse(n); 108 | pubkey = new PublicKey(n, g); 109 | prikey = new PrivateKey(lambda, mu); 110 | } 111 | /** 112 | * @Title: encrypt 113 | * @Description: This function is to encrypt the message 114 | * with Paillier’s public key. 115 | * @param m 116 | * The message. 117 | * @param pubkey 118 | * The public key of Paillier PKE. 119 | * @return BigInteger The ciphertext. 120 | * @throws Exception 121 | * If the message is not in Z*_n, there is 122 | * an exception. 123 | */ 124 | public static BigInteger encrypt(BigInteger m, 125 | PublicKey pubkey) throws Exception { 126 | BigInteger n = pubkey.getN(); 127 | BigInteger nsquare = n.pow(2); 128 | BigInteger g = pubkey.getG(); 129 | if (!belongToZStarN(m, n)) { 130 | throw new Exception( 131 | "Paillier.encrypt(BigInteger m, PublicKey pubkey): plaintext m is not in Z*_n"); 132 | } 133 | BigInteger r = randomZStarN(n); 134 | return (g.modPow(m, nsquare).multiply(r.modPow(n, 135 | nsquare))).mod(nsquare); 136 | }/** 137 | * @Title: decrypt 138 | * @Description: This function is to decrypt the ciphertext 139 | * with the public key and the private key. 140 | * @param c 141 | * The ciphertext. 142 | * @param pubkey 143 | * The public key of Paillier PKE. 144 | * @param prikey 145 | * The private key of Paillier PKE. 146 | * @return BigInteger The plaintext. 147 | * @throws Exception 148 | * If the cipher is not in Z*_(n^2), there is 149 | * an exception. 150 | */ 151 | public static BigInteger decrypt(BigInteger c, PublicKey 152 | pubkey, PrivateKey prikey) throws Exception { 153 | BigInteger n = pubkey.getN(); 154 | BigInteger nsquare = n.pow(2); 155 | BigInteger lambda = prikey.getLambda(); 156 | BigInteger mu = prikey.getMu(); 157 | if (!belongToZStarNSquare(c, nsquare)) { 158 | throw new Exception( 159 | "Paillier.decrypt(BigInteger c, PrivateKey prikey): ciphertext c is not in Z*_(n^2)"); 160 | } 161 | return Lfunction(c.modPow(lambda, nsquare), n). 162 | multiply(mu).mod(n); 163 | } 164 | /** 165 | * @Title: add 166 | * @Description: The function supports the homomorphic 167 | * addition with two ciphertext. 168 | * @param c1 169 | * The ciphertext. 170 | * @param c2 171 | * The ciphertext. 172 | * @param pubkey 173 | * The public key of Paillier PKE. 174 | * @return BigInteger The return value is c1*c2 mod n^2. 175 | */ 176 | public static BigInteger add(BigInteger c1, BigInteger c2, 177 | PublicKey pubkey) {BigInteger nsquare = pubkey.getN() 178 | .pow(2);return c1.multiply(c2).mod(nsquare); 179 | } 180 | /** 181 | * @Title: mul 182 | * @Description: The function supports the homomorphic 183 | * multiplication with one ciphertext and one plaintext. 184 | * @param c 185 | * The ciphertext. 186 | * @param m 187 | * The plaintext. 188 | * @param pubkey 189 | * The public key of Paillier PKE. 190 | * @return BigInteger The return value is c^m mod n^2. 191 | */ 192 | public static BigInteger mul(BigInteger c, BigInteger m, 193 | PublicKey pubkey) {BigInteger nsquare = 194 | pubkey.getN().pow(2); 195 | return c.modPow(m, nsquare); 196 | } 197 | /** 198 | * @Title: selfBlind 199 | * @Description: The function supports the homomorphic 200 | * self-blinding with one ciphertext and one random number. 201 | * @param c 202 | * The ciphertext. 203 | * @param r 204 | * A random number in Z*_n. 205 | * @param pubkey 206 | * The public key of Paillier PKE. 207 | * @return BigInteger The return value is c*r^n mod n^2. 208 | */ 209 | public static BigInteger selfBlind(BigInteger c, 210 | BigInteger r, PublicKey pubkey) { 211 | BigInteger n = pubkey.getN(); 212 | BigInteger nsquare = n.pow(2); 213 | return c.multiply(r.modPow(n, nsquare)).mod(nsquare); 214 | } 215 | /** 216 | * @Title: Lfunction 217 | * @Description: This function is the L function which is 218 | * defined by Paillier PKE, L(mu)=(mu-1)/n. 219 | * @param mu 220 | * The input parameter. 221 | * @param n 222 | * n=p*q. 223 | * @return BigInteger The return value is (mu-1)/n. 224 | */ 225 | private static BigInteger Lfunction(BigInteger mu, 226 | BigInteger n) {return 227 | mu.subtract(BigInteger.ONE).divide(n); 228 | } 229 | /** 230 | * @Title: randomZStarN 231 | * @Description: This function returns a ramdom number in 232 | * Z*_n. 233 | * @param n 234 | * n=p*q. 235 | * @return BigInteger A random number in Z*_n. 236 | */ 237 | public static BigInteger randomZStarN(BigInteger n) { 238 | BigInteger r; 239 | do { 240 | r = new BigInteger(n.bitLength(), new 241 | SecureRandom()); 242 | } while (r.compareTo(n) >= 0 || r.gcd(n).intValue() 243 | != 1); 244 | return r; 245 | } 246 | /** 247 | * 248 | * @Title: belongToZStarN 249 | * @Description: This function is to test whether the 250 | * plaintext is in Z*_n. 251 | * @param m 252 | * The plaintext. 253 | * @param n 254 | * n=p*q. 255 | * @return boolean If it is true, the plaintext is Z*_n, 256 | * otherwise, not. 257 | */ 258 | private static boolean belongToZStarN(BigInteger m, 259 | BigInteger n) { 260 | if (m.compareTo(BigInteger.ZERO) < 0 || 261 | m.compareTo(n) >= 0 262 | || m.gcd(n).intValue() != 1) { 263 | return false; 264 | } 265 | return true; 266 | } 267 | /** 268 | * 269 | * @Title: belongToZStarNSquare 270 | * @Description: This function is to test whether the 271 | * ciphertext is in 272 | * Z*_(n^2). 273 | * @param c 274 | * The ciphertext. 275 | * @param nsquare 276 | * nsquare=n^2. 277 | * @return boolean If it is true, the ciphertext is 278 | * Z*_(n^2), otherwise, not. 279 | */ 280 | private static boolean belongToZStarNSquare(BigInteger c, 281 | BigInteger nsquare){ 282 | if (c.compareTo(BigInteger.ZERO) < 0 || 283 | c.compareTo(nsquare) >= 0 284 | || c.gcd(nsquare).intValue() != 1) { 285 | return false; 286 | } 287 | return true; 288 | } 289 | public static void main(String[] args) { 290 | Paillier paillier = new Paillier(); 291 | // KeyGeneration 292 | paillier.keyGeneration(512); 293 | Paillier.PublicKey pubkey = paillier.getPubkey(); 294 | Paillier.PrivateKey prikey = paillier.getPrikey(); 295 | // Encryption and Decryption 296 | BigInteger m = new BigInteger(new String("Hello").getBytes()); 297 | BigInteger c = null; 298 | BigInteger decrypted_m = null; 299 | try { 300 | c = Paillier.encrypt(m, pubkey); 301 | decrypted_m = Paillier.decrypt(c, pubkey, prikey); 302 | } catch (Exception e) { 303 | // TODO Auto-generated catch block 304 | e.printStackTrace(); 305 | } 306 | if (decrypted_m.compareTo(m) == 0) { 307 | System.out.println("Encryption and Decryption test successfully."); 308 | } 309 | // Homomorphic Properties 310 | // Addition 311 | BigInteger m1 = new BigInteger("12345"); 312 | BigInteger m2 = new BigInteger("56789"); 313 | BigInteger m1plusm2 = m1.add(m2); 314 | try { 315 | BigInteger c1 = Paillier.encrypt(m1, pubkey); 316 | BigInteger c2 = Paillier.encrypt(m2, pubkey); 317 | BigInteger c1mulc2 = Paillier.add(c1, c2, pubkey); 318 | BigInteger decrypted_c1mulc2 = 319 | Paillier.decrypt(c1mulc2, pubkey, prikey); 320 | if (decrypted_c1mulc2.compareTo(m1plusm2) == 0) { 321 | System.out.println("Homomorphic addition tests successfully."); 322 | } 323 | } catch (Exception e) { 324 | e.printStackTrace(); 325 | } 326 | // Multiplication 327 | m1 = new BigInteger("12345"); 328 | m2 = new BigInteger("56789"); 329 | BigInteger m1mulm2 = m1.multiply(m2); 330 | try { 331 | BigInteger c1 = Paillier.encrypt(m1, pubkey); 332 | BigInteger c1expm2 = Paillier.mul(c1, m2, pubkey); 333 | BigInteger decrypted_c1expm2 = 334 | Paillier.decrypt(c1expm2, pubkey, prikey); 335 | if (decrypted_c1expm2.compareTo(m1mulm2) == 0) { 336 | System.out.println("Homomorphic multiplication tests successfully."); 337 | } 338 | } catch (Exception e) { 339 | e.printStackTrace(); 340 | } 341 | // Self-Blinding 342 | m1 = new BigInteger("12345"); 343 | BigInteger r2 = Paillier.randomZStarN(pubkey.getN()); 344 | try { 345 | BigInteger c1 = Paillier.encrypt(m1, pubkey); 346 | BigInteger c1mulrn = Paillier.selfBlind(c1, r2, 347 | pubkey); 348 | BigInteger decrypted_c1mulrn = 349 | Paillier.decrypt(c1mulrn, pubkey, prikey); 350 | if (decrypted_c1mulrn.compareTo(m1) == 0) { 351 | System.out.println("Homomorphic self-blinding tests successfully."); 352 | } 353 | } catch (Exception e) { 354 | e.printStackTrace(); 355 | } 356 | } 357 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cryptography 2 | This Projects has implemented three asymmetric and homomorphic encryption BGN, Benaloh, Paillier in Java using JPBC library. 3 | --------------------------------------------------------------------------------