/*
 * 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.cryptoapi;

import java.util.List;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.elgamal.bean.ElGamalPrivateKey;
import com.scytl.cryptolib.elgamal.bean.ElGamalPublicKey;
import com.scytl.cryptolib.elgamal.cryptoapi.Ciphertext;
import com.scytl.cryptolib.elgamal.cryptoapi.Witness;
import com.scytl.cryptolib.mathematical.groups.impl.ZpGroupElement;
import com.scytl.cryptolib.proofs.bean.ProofPreComputedValues;
import com.scytl.cryptolib.proofs.proof.Proof;

/**
 * Interface which defines an API that allows a number of Zero Knowledge Proofs
 * (ZKPs) to be generated.
 * <P>
 * Note: some of the proofs that may be created using this API have very similar
 * names, and they are used for similar, but slightly different reasons, i.e. to
 * prove different facts. Care must be taken to ensure that the correct type of
 * proof is being created.
 * <P>
 * Later, when a proof is being verified, care must be taken to ensure that the
 * correct verify method is used.
 */
public interface ProofProverAPI {

    /**
     * Creates a "Schnorr proof".
     * 
     * @param voterID
     *            the voter ID.
     * @param electionEventID
     *            the election event ID.
     * @param exponentiatedGenerator
     *            the exponentiated generator.
     * @param witness
     *            the witness.
     * @return the created {@code Proof}.
     * @throws GeneralCryptoLibException
     *             if the voter ID or election event ID is null, empty or
     *             contains only white spaces, the exponentiated generator
     *             element is null, or the witness is null.
     */
    Proof createSchnorrProof(final String voterID,
            final String electionEventID,
            final ZpGroupElement exponentiatedGenerator,
            final Witness witness) throws GeneralCryptoLibException;

    /**
     * Creates a "schnorr proof", using pre-computed values.
     * 
     * @param voterID
     *            the voter ID.
     * @param electionEventID
     *            the election event ID.
     * @param exponentiatedElement
     *            the exponentiated element.
     * @param witness
     *            the witness.
     * @param preComputedValues
     *            the proof pre-computed values.
     * @return the created {@code Proof}.
     * @throws GeneralCryptoLibException
     *             if the voter ID or election event ID is null, empty or
     *             contains only white spaces, the exponentiated generator
     *             element is null, the witness is null, or the pre-computed
     *             values object is null.
     */
    Proof createSchnorrProof(final String voterID,
            final String electionEventID,
            final ZpGroupElement exponentiatedElement,
            final Witness witness,
            final ProofPreComputedValues preComputedValues)
            throws GeneralCryptoLibException;

    /**
     * Creates an "exponentiation proof".
     * 
     * @param exponentiatedElements
     *            the list of exponentiated elements.
     * @param baseElements
     *            the list of base elements.
     * @param witness
     *            the witness.
     * @return the created {@code Proof}.
     * @throws GeneralCryptoLibException
     *             if the list of exponentiated elements or base elements is
     *             null, empty or contains one or more null elements, or the
     *             witness is null.
     */
    Proof createExponentiationProof(
            final List<ZpGroupElement> exponentiatedElements,
            final List<ZpGroupElement> baseElements, final Witness witness)
            throws GeneralCryptoLibException;

    /**
     * Creates an "exponentiation proof", using pre-computed values.
     * 
     * @param exponentiatedElements
     *            the list of exponentiated elements.
     * @param baseElements
     *            the list of base elements.
     * @param witness
     *            the witness.
     * @param preComputedValues
     *            the proof pre-computed values.
     * @return the created {@code Proof}.
     * @throws GeneralCryptoLibException
     *             if the list of exponentiated elements or base elements is
     *             null, empty or contains one or more null elements, the
     *             witness is null, or the pre-computed values object is null.
     */
    Proof createExponentiationProof(
            final List<ZpGroupElement> exponentiatedElements,
            final List<ZpGroupElement> baseElements, final Witness witness,
            final ProofPreComputedValues preComputedValues)
            throws GeneralCryptoLibException;

    /**
     * Creates a "decryption proof".
     * 
     * @param publicKey
     *            the public key.
     * @param ciphertext
     *            the ciphertext.
     * @param plaintext
     *            the plaintext.
     * @param privateKey
     *            the private key.
     * @return the created {@code Proof}.
     * @throws GeneralCryptoLibException
     *             if the ElGamal public key or the ciphertext is null, the
     *             plaintext is null, empty or contains one or more null
     *             elements, or the ElGamal private key is null.
     */
    Proof createDecryptionProof(final ElGamalPublicKey publicKey,
            final Ciphertext ciphertext,
            final List<ZpGroupElement> plaintext,
            final ElGamalPrivateKey privateKey)
            throws GeneralCryptoLibException;

    /**
     * Creates a "decryption proof", using pre-computed values.
     * 
     * @param publicKey
     *            the public key.
     * @param ciphertext
     *            the ciphertext.
     * @param plaintext
     *            the plaintext.
     * @param privateKey
     *            the private key.
     * @param preComputedValues
     *            the proof pre-computed values.
     * @return the created {@code Proof}.
     * @throws GeneralCryptoLibException
     *             if the ElGamal public key or the ciphertext is null, the
     *             plaintext is null, empty or contains one or more null
     *             elements, the ElGamal private key is null, or the
     *             pre-computed values object is null.
     */
    Proof createDecryptionProof(final ElGamalPublicKey publicKey,
            final Ciphertext ciphertext,
            final List<ZpGroupElement> plaintext,
            final ElGamalPrivateKey privateKey,
            final ProofPreComputedValues preComputedValues)
            throws GeneralCryptoLibException;

    /**
     * Creates a "plaintext proof".
     * 
     * @param publicKey
     *            the public key.
     * @param ciphertext
     *            the ciphertext.
     * @param plaintext
     *            the plaintext.
     * @param witness
     *            the witness.
     * @return the created {@code Proof}.
     * @throws GeneralCryptoLibException
     *             if the ElGamal public key or ciphertext is null, the
     *             plaintext is null, empty or contains one or more null
     *             elements, or the witness is null.
     */
    Proof createPlaintextProof(final ElGamalPublicKey publicKey,
            final Ciphertext ciphertext,
            final List<ZpGroupElement> plaintext, final Witness witness)
            throws GeneralCryptoLibException;

    /**
     * Creates a "plaintext proof", using pre-computed values.
     * 
     * @param publicKey
     *            the public key.
     * @param ciphertext
     *            the ciphertext.
     * @param plaintext
     *            the plaintext.
     * @param witness
     *            the witness.
     * @param preComputedValues
     *            the proof pre-computed values.
     * @return the created {@code Proof}.
     * @throws GeneralCryptoLibException
     *             if the ElGamal public key or ciphertext is null, the
     *             plaintext is null, empty or contains one or more null
     *             elements, the witness is null, or the pre-computed values
     *             object is null.
     */
    Proof createPlaintextProof(final ElGamalPublicKey publicKey,
            final Ciphertext ciphertext,
            final List<ZpGroupElement> plaintext, final Witness witness,
            final ProofPreComputedValues preComputedValues)
            throws GeneralCryptoLibException;

    /**
     * Creates a "simple plaintext equality proof".
     * 
     * @param primaryCiphertext
     *            the primary ciphertext.
     * @param primaryPublicKey
     *            the primary public key.
     * @param witness
     *            the witness.
     * @param secondaryCiphertext
     *            the secondary ciphertext.
     * @param secondaryPublicKey
     *            the secondary public key.
     * @return the created {@code Proof}.
     * @throws GeneralCryptoLibException
     *             if the primary ciphertext, primary ElGamal public key,
     *             witness, secondary ciphertext or secondary ElGamal public key
     *             is null.
     */
    Proof createSimplePlaintextEqualityProof(
            final Ciphertext primaryCiphertext,
            final ElGamalPublicKey primaryPublicKey, final Witness witness,
            final Ciphertext secondaryCiphertext,
            final ElGamalPublicKey secondaryPublicKey)
            throws GeneralCryptoLibException;

    /**
     * Creates a "simple plaintext equality proof", using pre-computed values.
     * 
     * @param primaryCiphertext
     *            the primary ciphertext.
     * @param primaryPublicKey
     *            the primary public key.
     * @param witness
     *            the witness.
     * @param secondaryCiphertext
     *            the secondary ciphertext.
     * @param secondaryPublicKey
     *            the secondary public key.
     * @param preComputedValues
     *            the proof pre-computed values.
     * @return the created {@code Proof}.
     * @throws GeneralCryptoLibException
     *             if the primary ciphertext, primary ElGamal public key,
     *             witness, secondary ciphertext, secondary ElGamal public key
     *             or pre-computed values object is null.
     */
    Proof createSimplePlaintextEqualityProof(
            final Ciphertext primaryCiphertext,
            final ElGamalPublicKey primaryPublicKey, final Witness witness,
            final Ciphertext secondaryCiphertext,
            final ElGamalPublicKey secondaryPublicKey,
            final ProofPreComputedValues preComputedValues)
            throws GeneralCryptoLibException;

    /**
     * Creates a "plaintext equality proof".
     * 
     * @param primaryCiphertext
     *            the primary ciphertext.
     * @param primaryPublicKey
     *            the primary public key.
     * @param primaryWitness
     *            the primary witness.
     * @param secondaryCiphertext
     *            the secondary ciphertext.
     * @param secondaryPublicKey
     *            the secondary public key.
     * @param secondaryWitness
     *            the secondary witness.
     * @return the created {@code Proof}.
     * @throws GeneralCryptoLibException
     *             if there are any problems with the inputs.
     * @deprecated since 1.31.0-alpha. Should replace this method with the
     *             method of the same name, that takes the primary and secondary
     *             ciphertext input arguments as
     *             {@link com.scytl.cryptolib.elgamal.cryptoapi.Ciphertext}
     *             objects instead of as lists of
     *             {@link com.scytl.cryptolib.mathematical.groups.impl.ZpGroupElement}
     *             objects, which is now consistent with the API for the other
     *             plaintext proofs. The method that should now be used is
     *             {@link #createPlaintextEqualityProof(Ciphertext, ElGamalPublicKey, Witness, Ciphertext, ElGamalPublicKey, Witness)}
     */
    @Deprecated
    Proof createPlaintextEqualityProof(
            final List<ZpGroupElement> primaryCiphertext,
            final ElGamalPublicKey primaryPublicKey,
            final Witness primaryWitness,
            final List<ZpGroupElement> secondaryCiphertext,
            final ElGamalPublicKey secondaryPublicKey,
            final Witness secondaryWitness)
            throws GeneralCryptoLibException;

    /**
     * Creates a "plaintext equality proof".
     * 
     * @param primaryCiphertext
     *            the primary ciphertext.
     * @param primaryPublicKey
     *            the primary public key.
     * @param primaryWitness
     *            the primary witness.
     * @param secondaryCiphertext
     *            the secondary ciphertext.
     * @param secondaryPublicKey
     *            the secondary public key.
     * @param secondaryWitness
     *            the secondary witness.
     * @return the created {@code Proof}.
     * @throws GeneralCryptoLibException
     *             if the primary ciphertext, primary ElGamal public key,
     *             primary witness, secondary ciphertext, secondary ElGamal
     *             public key or secondary witness is null.
     */
    Proof createPlaintextEqualityProof(final Ciphertext primaryCiphertext,
            final ElGamalPublicKey primaryPublicKey,
            final Witness primaryWitness,
            final Ciphertext secondaryCiphertext,
            final ElGamalPublicKey secondaryPublicKey,
            final Witness secondaryWitness)
            throws GeneralCryptoLibException;

    /**
     * Creates a "plaintext equality proof", using pre-computed values.
     * 
     * @param primaryCiphertext
     *            the primary ciphertext.
     * @param primaryPublicKey
     *            the primary public key.
     * @param primaryWitness
     *            the primary witness.
     * @param secondaryCiphertext
     *            the secondary ciphertext.
     * @param secondaryPublicKey
     *            the secondary public key.
     * @param secondaryWitness
     *            the secondary witness.
     * @param preComputedValues
     *            the proof pre-computed values.
     * @return the created {@code Proof}.
     * @throws GeneralCryptoLibException
     *             if the primary ciphertext, primary ElGamal public key,
     *             primary witness, secondary ciphertext, secondary ElGamal
     *             public key, secondary witness or pre-computed values object
     *             is null.
     */
    Proof createPlaintextEqualityProof(final Ciphertext primaryCiphertext,
            final ElGamalPublicKey primaryPublicKey,
            final Witness primaryWitness,
            final Ciphertext secondaryCiphertext,
            final ElGamalPublicKey secondaryPublicKey,
            final Witness secondaryWitness,
            final ProofPreComputedValues preComputedValues)
            throws GeneralCryptoLibException;

    /**
     * Creates a "plaintext exponent equality proof".
     * 
     * @param ciphertext
     *            the ciphertext.
     * @param baseElements
     *            the list of base elements.
     * @param witness1
     *            the first witness.
     * @param witness2
     *            the second witness.
     * @return the created {@code Proof}.
     * @throws GeneralCryptoLibException
     *             if the ciphertext is null, the list of base elements is null,
     *             empty or contains one or more null elements, or the first or
     *             second witness is null.
     */
    Proof createPlaintextExponentEqualityProof(final Ciphertext ciphertext,
            final List<ZpGroupElement> baseElements,
            final Witness witness1, final Witness witness2)
            throws GeneralCryptoLibException;

    /**
     * Creates a "plaintext exponent equality proof", using pre-computed values.
     * 
     * @param ciphertext
     *            the encrypted list of base elements.
     * @param baseElements
     *            the list of base elements.
     * @param witness1
     *            the witness that wraps the ephemeral key exponent.
     * @param witness2
     *            the witness that wraps the message exponent.
     * @param preComputedValues
     *            the proof pre-computed values.
     * @return the created {@code Proof}.
     * @throws GeneralCryptoLibException
     *             if the ciphertext is null, the list of base elements is null,
     *             empty or contains one or more null elements, the first or
     *             second witness is null, or the pre-computed values object is
     *             null.
     */
    Proof createPlaintextExponentEqualityProof(final Ciphertext ciphertext,
            final List<ZpGroupElement> baseElements,
            final Witness witness1, final Witness witness2,
            final ProofPreComputedValues preComputedValues)
            throws GeneralCryptoLibException;

    /**
     * Creates an "OR proof". The returned proof ensures that the specified
     * ciphertext is an ElGamal encryption of one of the given group elements.
     * 
     * @param ciphertext
     *            the ciphertext
     * @param publicKey
     *            the ElGamal public key used for the encryption
     * @param witness
     *            the secret exponent used for the encryption
     * @param index
     *            the index of the encrypted group element
     * @param elements
     *            the group elements
     * @param data
     *            the string data to be included into hash
     * @return the OR proof
     * @throws GeneralCryptoLibException
     *             failed to create a OR proof.
     */
    Proof createORProof(Ciphertext ciphertext, ElGamalPublicKey publicKey,
            Witness witness, int index, List<ZpGroupElement> elements,
            String data) throws GeneralCryptoLibException;

    /**
     * Creates an "OR proof", using pre-computed values. The returned proof
     * ensures that the specified ciphertext is an ElGamal encryption of one of
     * the given group elements.
     * 
     * @param ciphertext
     *            the ciphertext
     * @param publicKey
     *            the ElGamal public key used for the encryption
     * @param witness
     *            the secret exponent used for the encryption
     * @param index
     *            the index of the encrypted group element
     * @param elements
     *            the group elements
     * @param data
     *            the string data to be included into hash
     * @param preComputedValues
     *            the proof pre-computed values
     * @return the OR proof
     * @throws GeneralCryptoLibException
     *             failed to create a OR proof.
     */
    Proof createORProof(Ciphertext ciphertext, ElGamalPublicKey publicKey,
            Witness witness, int index, List<ZpGroupElement> elements,
            String data, ProofPreComputedValues preComputedValues)
            throws GeneralCryptoLibException;
}
