package gr.duth.eece.cryptographyLesson.asymmetric.paillier;

import java.io.Serializable;
import java.math.BigInteger;
import java.security.SecureRandom;

public class PaillierKeyPair implements Serializable{

	public PaillierPublicKey PublicKey;
	public PaillierPrivateKey PrivateKey;

	public PaillierKeyPair(int bitLengthVal) {
		// TODO Auto-generated constructor stub
		KeyGeneration(bitLengthVal, 100);
	}

	private void KeyGeneration(int bitLengthVal, int certainty) {
		int bitLength = bitLengthVal;
		/*Constructs two randomly generated positive BigIntegers that are probably prime, with the specified bitLength and certainty.*/
		BigInteger p = new BigInteger(bitLength / 2, certainty, new SecureRandom());
		BigInteger q = new BigInteger(bitLength / 2, certainty, new SecureRandom());

		BigInteger n = p.multiply(q);
		BigInteger nsquare = n.multiply(n);
		BigInteger g, lambda;
		while(true){
			g = new BigInteger(bitLength, new SecureRandom());
			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, nsquare).subtract(BigInteger.ONE).divide(n).gcd(n).intValue() != 1) {
				System.out.println("g is not good. Choose g again.");
				//System.exit(1);
			}else{
				break;
			}
		}
		PublicKey = new PaillierPublicKey();
		PublicKey.bitLength = bitLength;
		PublicKey.n = n;
		PublicKey.nsquare = nsquare;
		PublicKey.g = g;

		PrivateKey = new PaillierPrivateKey();
		PrivateKey.bitLength = bitLength;
		PrivateKey.n = n;
		PrivateKey.nsquare = nsquare;
		PrivateKey.lambda = lambda;
		PrivateKey.u = g.modPow(lambda, nsquare).subtract(BigInteger.ONE).divide(n).modInverse(n);
	}

}
