/*
 * 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 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.ZpSubgroup;
import com.scytl.cryptolib.primitives.securerandom.factory.CryptoRandomInteger;
import com.scytl.cryptolib.primitives.securerandom.factory.SecureRandomFactory;
import com.scytl.cryptolib.proofs.maurer.configuration.MaurerProofPolicy;

/**
 * Factory class that can create prover, verifier and pre-computer objects, as
 * well as implementations of the prover, verifier and pre-computer APIs.
 *
 * @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 final class MaurerUnifiedProofFactory<T, E extends GroupElement<T>> {

    private final MaurerProofPolicy _maurerProofPolicy;

    /**
     * Creates an instance of the class and initializes it with the provided
     * policy.
     *
     * @param maurerProofPolicy
     *            the policy.
     */
    public MaurerUnifiedProofFactory(
            final MaurerProofPolicy maurerProofPolicy) {

        _maurerProofPolicy = maurerProofPolicy;
    }

    /**
     * Creates a {@code ZpSubgroupProofProver} that may be used for generating
     * various proofs.
     *
     * @param group
     *            the mathematical group over which the proofs operate.
     * @return a {@code ProofProverAPI} which provides methods for creating
     *         various proofs.
     * @throws GeneralCryptoLibException
     *             if {@code group} is not a valid mathematical group.
     */
    public ZpSubgroupProofProver createProofCreationAPI(
            final MathematicalGroup<?> group)
            throws GeneralCryptoLibException {

        CryptoRandomInteger cryptoRandomInteger =
            new SecureRandomFactory(_maurerProofPolicy)
                .createIntegerRandom();

        return new ZpSubgroupProofProver(group,
            _maurerProofPolicy.getMessageDigestAlgorithmAndProvider(),
            _maurerProofPolicy.getCharset(), cryptoRandomInteger);
    }

    /**
     * Creates a {@code ZpSubgroupProofVerifier} that may be used for verifying
     * various proofs. Sets {@code group} as the mathematical group over which
     * the proofs operate.
     *
     * @param group
     *            the mathematical group that should be set in the created
     *            {@code ProofVerifierAPI}.
     * @return a {@code ZpSubgroupProofVerifier} which provides methods for
     *         verifying various proofs.
     * @throws GeneralCryptoLibException
     *             if {@code group} is not a valid mathematical group.
     */
    public ZpSubgroupProofVerifier createProofVerificationAPI(
            final MathematicalGroup<?> group)
            throws GeneralCryptoLibException {

        return new ZpSubgroupProofVerifier(group,
            _maurerProofPolicy.getMessageDigestAlgorithmAndProvider(),
            _maurerProofPolicy.getCharset());
    }

    /**
     * Creates a {@code ZpSubgroupProofPreComputer} that may be used for
     * pre-computing values needed to generate or verify various proofs. Sets
     * {@code group} as the mathematical group over which the proofs operate.
     *
     * @param group
     *            the mathematical group that should be set in the created
     *            {@code ProofPreComputerAPI}.
     * @return a {@code ZpSubgroupProofPreComputer} which provides methods for
     *         pre-computing the proof generation or verification values.
     * @throws GeneralCryptoLibException
     *             if {@code group} is not a valid mathematical group.
     */
    public ZpSubgroupProofPreComputer createProofPreComputationAPI(
            final MathematicalGroup<?> group)
            throws GeneralCryptoLibException {

        CryptoRandomInteger cryptoRandomInteger =
            new SecureRandomFactory(_maurerProofPolicy)
                .createIntegerRandom();

        return new ZpSubgroupProofPreComputer((ZpSubgroup) group,
            _maurerProofPolicy.getMessageDigestAlgorithmAndProvider(),
            _maurerProofPolicy.getCharset(), cryptoRandomInteger);
    }
}
