/*
 * 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 java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

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

import org.junit.Before;
import org.junit.Test;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.elgamal.bean.CiphertextImpl;
import com.scytl.cryptolib.elgamal.bean.ElGamalPublicKey;
import com.scytl.cryptolib.elgamal.bean.WitnessImpl;
import com.scytl.cryptolib.elgamal.cryptoapi.Ciphertext;
import com.scytl.cryptolib.elgamal.cryptoapi.Witness;
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.mathematical.groups.utils.MathematicalTestDataGenerator;
import com.scytl.cryptolib.primitives.messagedigest.configuration.ConfigMessageDigestAlgorithmAndProvider;
import com.scytl.cryptolib.primitives.service.PrimitivesService;
import com.scytl.cryptolib.proofs.bean.ProofPreComputedValues;
import com.scytl.cryptolib.proofs.maurer.configuration.ConfigProofHashCharset;
import com.scytl.cryptolib.proofs.proof.Proof;
import com.scytl.cryptolib.securerandom.cryptoapi.CryptoAPIRandomInteger;

/**
 * Tests of {@link ORProofVerifier}.
 */
public class ORProofVerifierTest {
    private static final String DATA = "data";

    private static final int INDEX = 1;

    private ZpSubgroup group;

    private ElGamalPublicKey publicKey;

    private List<ZpGroupElement> elements;

    private Ciphertext ciphertext;

    private Witness witness;

    private Proof proof;

    @Before
    public void setUp() throws GeneralCryptoLibException {
        group = MathematicalTestDataGenerator.getZpSubgroup();

        Exponent privateKey =
            new Exponent(group.getQ(), BigInteger.valueOf(2));
        List<ZpGroupElement> keys =
            singletonList(group.getGenerator().exponentiate(privateKey));
        publicKey = new ElGamalPublicKey(keys, group);

        elements = asList(group.getGenerator(),
            group.getGenerator().multiply(group.getGenerator()),
            group.getGenerator().multiply(group.getGenerator())
                .multiply(group.getGenerator()));

        Exponent a = new Exponent(group.getQ(), BigInteger.valueOf(3));
        
        ciphertext = new CiphertextImpl(
            group.getGenerator().exponentiate(a), publicKey.getKeys()
                .get(0).exponentiate(a).multiply(elements.get(INDEX)));

        witness = new WitnessImpl(a);

        CryptoAPIRandomInteger random =
            new PrimitivesService().getCryptoRandomInteger();

        ORProofPreComputer preComputer =
            new ORProofPreComputer(publicKey, elements.size());

        ProofPreComputedValues preComputedValues =
            preComputer.preCompute(random);

        ORProofGenerator generator = new ORProofGenerator(ciphertext,
            publicKey, witness, INDEX, elements, DATA, random,
            ConfigMessageDigestAlgorithmAndProvider.SHA256_SUN,
            ConfigProofHashCharset.UTF8, preComputedValues);

        proof = generator.generate();

    }

    @Test
    public void testVerifyCorrect() throws GeneralCryptoLibException {
        ORProofVerifier verifier = new ORProofVerifier(ciphertext,
            publicKey, elements, DATA, proof, group,
            ConfigMessageDigestAlgorithmAndProvider.SHA256_SUN,
            ConfigProofHashCharset.UTF8);
        assertTrue(verifier.verify());
    }

    @Test
    public void testVerifyIncorrectData()
            throws GeneralCryptoLibException {
        ORProofVerifier verifier = new ORProofVerifier(ciphertext,
            publicKey, elements, DATA + "something else", proof, group,
            ConfigMessageDigestAlgorithmAndProvider.SHA256_SUN,
            ConfigProofHashCharset.UTF8);
        assertFalse(verifier.verify());
    }

    @Test
    public void testVerifyIncorrectElement()
            throws GeneralCryptoLibException {
        Exponent a = new Exponent(group.getQ(), BigInteger.valueOf(3));

        ciphertext = new CiphertextImpl(
            group.getGenerator().exponentiate(a), publicKey.getKeys()
            .get(0).exponentiate(a).multiply(elements.get(INDEX + 1)));

        ORProofVerifier verifier = new ORProofVerifier(ciphertext,
            publicKey, elements, DATA, proof, group,
            ConfigMessageDigestAlgorithmAndProvider.SHA256_SUN,
            ConfigProofHashCharset.UTF8);
        assertFalse(verifier.verify());
    }
}
