/*
 * 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.proofs.maurer.factory;

import static com.scytl.cryptolib.proofs.maurer.configuration.Constants.EXPONENTIATION_PROOF_AUXILIARY_DATA;

import java.util.ArrayList;
import java.util.List;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.mathematical.groups.GroupElement;
import com.scytl.cryptolib.mathematical.groups.MathematicalGroup;
import com.scytl.cryptolib.mathematical.groups.impl.Exponent;
import com.scytl.cryptolib.primitives.messagedigest.configuration.ConfigMessageDigestAlgorithmAndProvider;
import com.scytl.cryptolib.proofs.bean.ProofPreComputedValues;
import com.scytl.cryptolib.proofs.maurer.configuration.ConfigProofHashCharset;
import com.scytl.cryptolib.proofs.maurer.function.PhiFunctionExponentiation;
import com.scytl.cryptolib.proofs.proof.Proof;

/**
 * Generator of the zero knowledge proof of the exponent used to perform the
 * exponentiation operation on a collection of mathematical group elements.
 * 
 * @param <T>
 *            the type which parameterizes the group elements of the
 *            {@link MathematicalGroup} that will be used during this exchange.
 * @param <E>
 *            the type of the group elements of the {@link MathematicalGroup}
 *            that will be used during this exchange. E must be a type which
 *            extends GroupElement{@code <T>}.
 */
public class ExponentiationProofGenerator<T, E extends GroupElement<T>> {

    private final List<E> _exponentiatedElements;

    private final List<E> _baseElements;

    private final Exponent _exponent;

    private final MathematicalGroup<E> _group;

    private final ConfigMessageDigestAlgorithmAndProvider _configMessageDigestAlgorithmAndProvider;

    private final ConfigProofHashCharset _configProofHashCharset;

    private final ProofPreComputedValues _preComputedValues;

    /**
     * Default constructor.
     * 
     * @param exponentiatedElements
     *            the exponentiated base elements.
     * @param baseElements
     *            the base elements.
     * @param exponent
     *            the exponent, which acts as the witness for this proof.
     * @param group
     *            the Zp subgroup used for the exponentiation.
     * @param configMessageDigestAlgorithmAndProvider
     *            the algorithm and provider of the message digest used to
     *            generate the proof.
     * @param configProofHashCharset
     *            the character set of the hash used to generate the proof.
     * @param preComputedValues
     *            the pre-computed values used to generate the proof.
     * @throws GeneralCryptoLibException
     *             if the phi function cannot be created.
     */
    ExponentiationProofGenerator(
            final List<E> exponentiatedElements,
            final List<E> baseElements,
            final Exponent exponent,
            final MathematicalGroup<E> group,
            final ConfigMessageDigestAlgorithmAndProvider configMessageDigestAlgorithmAndProvider,
            final ConfigProofHashCharset configProofHashCharset,
            final ProofPreComputedValues preComputedValues)
            throws GeneralCryptoLibException {

        _exponentiatedElements = new ArrayList<>(exponentiatedElements);
        _baseElements = new ArrayList<>(baseElements);
        _exponent = exponent;
        _group = group;

        _configMessageDigestAlgorithmAndProvider =
            configMessageDigestAlgorithmAndProvider;
        _configProofHashCharset = configProofHashCharset;

        _preComputedValues = preComputedValues;
    }

    /**
     * Generates the exponentiation zero knowledge proof.
     * 
     * @return the exponentiation zero knowledge proof, as an object of type
     *         {@link Proof}.
     * @throws GeneralCryptoLibException
     *             if the @{ExponentiationProofGenerator} was instantiated by
     *             invalid arguments.
     */
    public Proof generate() throws GeneralCryptoLibException {

        PhiFunctionExponentiation<T> phiFunctionExponentiation =
            new PhiFunctionExponentiation<>(_group, _baseElements);

        Prover<T, E> prover =
            new Prover<>(_group, phiFunctionExponentiation,
                _configMessageDigestAlgorithmAndProvider,
                _configProofHashCharset);

        return prover.prove(_exponentiatedElements, buildListExponents(),
            EXPONENTIATION_PROOF_AUXILIARY_DATA, _preComputedValues);
    }

    private List<Exponent> buildListExponents() {

        List<Exponent> exponentList = new ArrayList<>();
        exponentList.add(_exponent);

        return exponentList;
    }
}
