/*
 * 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.cryptolib.elgamal.encrytionparams;

import java.math.BigInteger;

import com.scytl.cryptolib.api.exceptions.CryptoLibException;
import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.elgamal.bean.ElGamalEncryptionParameters;
import com.scytl.cryptolib.primitives.messagedigest.configuration.ConfigMessageDigestAlgorithmAndProvider;
import com.scytl.cryptolib.primitives.messagedigest.factory.CryptoMessageDigest;
import com.scytl.cryptolib.primitives.messagedigest.factory.MessageDigestFactory;
import com.scytl.cryptolib.securerandom.cryptoapi.CryptoAPIRandomBytes;

/**
 * A generator of ElGamal Encryption Parameters.
 */
public final class ElGamalEncryptionParamsGenerator
        implements SubgroupParamsGenerator {

    private final ElGamalEncryptionParametersGenerationParameters _dsaGenerationParametersWithCryptoRandomBytes;

    private final CryptoMessageDigest _digester;

    /**
     * Creates an ElGamal Encryption Parameters generator.
     *
     * @param L
     *            the length of p in bytes.
     * @param N
     *            the length of q in bytes.
     * @param certainty
     *            the certainty level for prime generating.
     * @param cryptoRandomBytes
     *            the course of random bytes that should be used when generating
     *            encryption parameters.
     */
    public ElGamalEncryptionParamsGenerator(final int L, final int N,
            final int certainty,
            final CryptoAPIRandomBytes cryptoRandomBytes) {

        MessageDigestFactory messageDigestFactorySHA256BC =
            new MessageDigestFactory(new MessageDigestPolicyImpl(
                ConfigMessageDigestAlgorithmAndProvider.SHA256_BC));
        _digester = messageDigestFactorySHA256BC.create();

        _dsaGenerationParametersWithCryptoRandomBytes =
            new ElGamalEncryptionParametersGenerationParameters(L, N,
                certainty, _digester, cryptoRandomBytes);
    }

    @Override
    public ElGamalEncryptionParameters generate() {

        EncryptionParameterGenerator encryptionParameterGenerator =
            new EncryptionParameterGenerator(
                _dsaGenerationParametersWithCryptoRandomBytes);
        try {

            // generate the p, q, seed, and counter (we currently dont use the
            // counter)
            EncryptionParametersPrimeOutputs primeOutputs =
                encryptionParameterGenerator
                    .generateParameters_FIPS186_3();

            BigInteger p = primeOutputs.getP();
            BigInteger q = primeOutputs.getQ();
            byte[] seed = primeOutputs.getSeed();

            // create g parameter (passing 1 as index)
            BigInteger g = encryptionParameterGenerator
                .calculateGenerator_FIPS186_3_Verifiable(_digester, p, q,
                    seed, 1);

            return new ElGamalEncryptionParameters(p, q, g);

        } catch (GeneralCryptoLibException e) {
            throw new CryptoLibException(
                "Exception while creating ElGamalEncryptionParameters using generator",
                e);
        }
    }
}
