/*
 * 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.channel.cc.choicecodes.verification.service;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import org.junit.Assert;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.elgamal.bean.ElGamalEncryptionParameters;
import com.scytl.cryptolib.elgamal.bean.ElGamalKeyPair;
import com.scytl.cryptolib.elgamal.bean.WitnessImpl;
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.cryptolib.proofs.cryptoapi.ProofProverAPI;
import com.scytl.cryptolib.proofs.cryptoapi.ProofVerifierAPI;
import com.scytl.cryptolib.proofs.proof.Proof;

public class ExponentiationProofGenerator {

    private final ElGamalEncryptionParameters ep;

    private final ProofProverAPI proofProverAPI;

    private final ProofVerifierAPI proofVerifierAPI;

    public ExponentiationProofGenerator(ProofProverAPI proofProver, ProofVerifierAPI proofVerifier,
            ElGamalEncryptionParameters ep)
            throws GeneralCryptoLibException {
        super();
        this.ep = ep;
        proofProverAPI = proofProver;
        proofVerifierAPI = proofVerifier;
    }

    public Proof createExponentiationProof(ElGamalKeyPair elGamalKeyPair, List<ZpGroupElement> zpGroupElements,
            List<ZpGroupElement> exponentiatedZpGroupElements)
            throws GeneralCryptoLibException {
        List<ZpGroupElement> modifiableZpGroupElements = new ArrayList<>(zpGroupElements);
        List<ZpGroupElement> modifiableExponentiateZpGroupElements = new ArrayList<>(exponentiatedZpGroupElements);

        final BigInteger generatorEncryptParamBigInteger = ep.getG();
        final ZpGroupElement groupElementGenerator =
            getZpGroupElement((ZpSubgroup) ep.getGroup(), generatorEncryptParamBigInteger);
        modifiableZpGroupElements.add(0, groupElementGenerator);

        ZpGroupElement verificationCardPublicKey = elGamalKeyPair.getPublicKeys().getKeys().get(0);
        Exponent exponent = elGamalKeyPair.getPrivateKeys().getKeys().get(0);
        Assert.assertEquals(verificationCardPublicKey, groupElementGenerator.exponentiate(exponent));
        modifiableExponentiateZpGroupElements.add(0, verificationCardPublicKey);

        Proof exponentiationProof = proofProverAPI.createExponentiationProof(modifiableExponentiateZpGroupElements,
            modifiableZpGroupElements, new WitnessImpl(exponent));

        Assert.assertTrue(proofVerifierAPI.verifyExponentiationProof(modifiableExponentiateZpGroupElements,
            modifiableZpGroupElements, exponentiationProof));

        return exponentiationProof;
    }

    private ZpGroupElement getZpGroupElement(final ZpSubgroup mathematicalGroup, final BigInteger value)
            throws GeneralCryptoLibException {
        final ZpGroupElement groupElement = new ZpGroupElement(value, mathematicalGroup);
        return groupElement;
    }

    public String[] getCiphertextElementsFromEncryptedOptions(String encryptedOptions) {
        return encryptedOptions.split(";");
    }
}
