/* * Copyright 2014 Christopher Mann * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.uni_bonn.bit; import org.bitcoinj.core.ECKey; import org.apache.avro.reflect.Nullable; import org.apache.avro.reflect.Stringable; import org.spongycastle.pqc.math.linearalgebra.IntegerFunctions; import java.math.BigInteger; import java.security.SecureRandom; /** * This class represents a key pair for the Paillier crypto system. It can contain either a complete key pair consisting * of a private key and the corresponding public key or only the public key. This class can generate key pairs, perform * encryption and decryption, and apply homomorphic operations to the cipher texts. */ public class PaillierKeyPair { @Stringable BigInteger n; @Stringable BigInteger g; @Stringable @Nullable BigInteger lambda; //PRIVATE KEY @Stringable @Nullable BigInteger my; //PRIVATE KEY public PaillierKeyPair() {} public PaillierKeyPair(int securityParameter) { SecureRandom sr = new SecureRandom(); BigInteger p = BigInteger.probablePrime(securityParameter / 2 + 1, sr); BigInteger q = BigInteger.probablePrime(securityParameter / 2 + 1, sr); n = p.multiply(q); lambda = lcm(p.subtract(BigInteger.ONE), q.subtract(BigInteger.ONE)); BigInteger nsquare = n.multiply(n); //better choice for g by Damgard & Jurik (2001) g = n.add(BigInteger.ONE); my = L(g.modPow(lambda, nsquare)).modInverse(n); } public BigInteger encrypt(BigInteger message){ if(message.compareTo(n) >= 0) throw new IllegalArgumentException("The message is to large for the group."); BigInteger r = generateRandomizer(); return encrypt(message, r); } public BigInteger generateRandomizer(){ return IntegerFunctions.randomize(n.subtract(BigInteger.ONE)).add(BigInteger.ONE); } public BigInteger encrypt(BigInteger message, BigInteger r){ if(message.compareTo(n) >= 0) throw new IllegalArgumentException("The message is to large for the group."); if(r.compareTo(n) >= 0) throw new IllegalArgumentException("The randomizer r is to large for the group."); BigInteger nsquare = n.multiply(n); BigInteger c = g.modPow(message, nsquare).multiply(r.modPow(n, nsquare)).mod(nsquare); return c; } public BigInteger decrypt(BigInteger ciphertext){ BigInteger nsquare = n.multiply(n); if(ciphertext.compareTo(nsquare) >= 0) throw new IllegalArgumentException("The cipher text is to large."); BigInteger m = L(ciphertext.modPow(lambda, nsquare)).multiply(my).mod(n); return m; } public BigInteger multiplyWithScalar(BigInteger c, BigInteger scalar){ return c.modPow(scalar, n.multiply(n)); } public BigInteger add(BigInteger a, BigInteger b){ return a.multiply(b).mod(n.multiply(n)); } public static BigInteger lcm(BigInteger a, BigInteger b){ return a.divide(a.gcd(b)).multiply(b); } public BigInteger L(BigInteger u){ return u.subtract(BigInteger.ONE).divide(n); } /** * Returns a copy of this key pair which only contains the public key. All private information has been removed. */ public PaillierKeyPair clearPrivateKey(){ PaillierKeyPair result = new PaillierKeyPair(); result.n = this.n; result.g = this.g; //private key part to null result.lambda = null; result.my = null; return result; } public boolean containsPrivateKey(){ return lambda != null || my != null; } public BigInteger getN() { return n; } public BigInteger getG() { return g; } public static PaillierKeyPair generatePaillierKeyPair(){ //The protocol requires a minimal bitlength of |n|*9 (in ZKProof section), using |n|*10 int minBitLength = ECKey.CURVE.getN().bitLength() * 10; //This is RSA modules -> we want at least 2048 bits for security int secParam = 2048 > minBitLength ? 2048 : minBitLength; return new PaillierKeyPair(secParam); } }