/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.products.ov.mixnet.commons.tools;

import java.math.BigInteger;

import com.scytl.cryptolib.api.exceptions.CryptoLibException;
import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.mathematical.groups.impl.Exponent;
import com.scytl.cryptolib.mathematical.groups.impl.ZpGroupElement;
import com.scytl.cryptolib.mathematical.groups.impl.ZpSubgroup;
import com.scytl.math.BigIntegers;

public class GroupTools {

	/**
	 * Non-public constructor
	 */
	private GroupTools() {
	}
		
	public static ZpSubgroup createGroupWithRandomGenerator(BigInteger p, BigInteger q) {

        try {

            BigInteger auxgen = BigIntTools.generateBigInteger(p);

            while ((auxgen.compareTo(BigInteger.ONE) == 0)
                || (BigIntegers.modPow(auxgen, q, p).compareTo(BigInteger.ONE) != 0)) {
                auxgen = BigIntTools.generateBigInteger(p);
            }
            return new ZpSubgroup(auxgen, p, q);

        } catch (GeneralCryptoLibException e) {
            throw new CryptoLibException(e);
        }
    }

    public static ZpGroupElement getRandomGeneratorFromPandQ(BigInteger p, BigInteger q) {

        try {

            BigInteger auxgen = BigIntTools.generateBigInteger(p);

            while ((auxgen.compareTo(BigInteger.ONE) == 0)
                || (BigIntegers.modPow(auxgen, q, p).compareTo(BigInteger.ONE) != 0)) {
                auxgen = BigIntTools.generateBigInteger(p);
            }
            return new ZpGroupElement(auxgen, p, q);

        } catch (GeneralCryptoLibException e) {
            throw new CryptoLibException(e);
        }
    }

    public static ZpGroupElement getRandomElement(ZpSubgroup group) {

        try {

            Exponent randomExponent = ExponentTools.getRandomExponent(group.getQ());

            return group.getGenerator().exponentiate(randomExponent);

        } catch (GeneralCryptoLibException e) {
            throw new CryptoLibException(e);
        }
    }

    public static ZpGroupElement[] getVectorRandomElement(ZpSubgroup group, int length) {

        ZpGroupElement[] result = new ZpGroupElement[length];
        for (int i = 0; i < result.length; i++) {
            result[i] = getRandomElement(group);
        }
        return result;
    }

    public static boolean isGroupElement(ZpGroupElement zpGroupElement) {
        BigInteger value = zpGroupElement.getValue();
        return value.compareTo(BigInteger.ZERO) >= 0
            && value.compareTo(zpGroupElement.getP()) < 0
            && BigInteger.ONE.equals(BigIntegers.modPow(value,
                zpGroupElement.getQ(), zpGroupElement.getP()));
    }
}
