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

import static org.junit.Assert.assertEquals;

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

import org.junit.BeforeClass;
import org.junit.Test;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.mathematical.groups.impl.Exponent;
import com.scytl.cryptolib.mathematical.groups.impl.ZpGroupElement;
import com.scytl.cryptolib.mathematical.groups.impl.ZpSubgroup;

/**
 * Tests of ElGamalKeyPair.
 */
public class ElGamalKeyPairTest {

    private static BigInteger _p;

    private static BigInteger _q;

    private static BigInteger _g;

    private static ZpSubgroup _group;

    private static List<Exponent> _privKeys;

    private static List<ZpGroupElement> _pubKeys;

    private static ElGamalPrivateKey _elGamalPrivateKey;

    private static ElGamalPublicKey _elGamalPublicKey;

    private static ElGamalKeyPair _elGamalKeyPair;

    @BeforeClass
    public static void setUp() throws GeneralCryptoLibException {

        _p = new BigInteger("23");

        _q = new BigInteger("11");

        _g = new BigInteger("2");

        _group = new ZpSubgroup(_g, _p, _q);

        // create the private key
        _privKeys = new ArrayList<Exponent>();
        _privKeys.add(new Exponent(_q, new BigInteger("4")));
        _privKeys.add(new Exponent(_q, new BigInteger("5")));
        _elGamalPrivateKey = new ElGamalPrivateKey(_privKeys, _group);

        // create the public key
        _pubKeys = new ArrayList<ZpGroupElement>();
        _pubKeys.add(new ZpGroupElement(_g, _group));
        _pubKeys.add(new ZpGroupElement(_g, _group));
        _elGamalPublicKey = new ElGamalPublicKey(_pubKeys, _group);

        // create the key pair
        _elGamalKeyPair =
            new ElGamalKeyPair(_elGamalPrivateKey, _elGamalPublicKey);
    }

    @Test(expected = GeneralCryptoLibException.class)
    public void givenNullPrivateKeyWhenCreateKeyPairThenException()
            throws GeneralCryptoLibException {

        ElGamalPrivateKey nullPrivateKey = null;
        new ElGamalKeyPair(nullPrivateKey, _elGamalPublicKey);
    }

    @Test(expected = GeneralCryptoLibException.class)
    public void givenNullPublicKeyWhenCreateKeyPairThenException()
            throws GeneralCryptoLibException {

        ElGamalPublicKey nullPublicKey = null;
        new ElGamalKeyPair(_elGamalPrivateKey, nullPublicKey);
    }

    @Test(expected = GeneralCryptoLibException.class)
    public void givenKeyListsWithDifferentNumbersOfElementsWhenCreateKeyPairThenException()
            throws GeneralCryptoLibException {

        // create public key with more elements than the private key
        List<ZpGroupElement> pubKeys = new ArrayList<ZpGroupElement>();
        pubKeys.add(new ZpGroupElement(_g, _group));
        pubKeys.add(new ZpGroupElement(_g, _group));
        pubKeys.add(new ZpGroupElement(_g, _group));
        ElGamalPublicKey elGamalPublicKeyLarger =
            new ElGamalPublicKey(pubKeys, _group);

        new ElGamalKeyPair(_elGamalPrivateKey, elGamalPublicKeyLarger);
    }

    @Test(expected = GeneralCryptoLibException.class)
    public void givenKeyListsFromDifferentGroupsWhenCreateKeyPairThenException()
            throws GeneralCryptoLibException {

        BigInteger differentQ = new BigInteger("3");
        ZpSubgroup smallGroup = new ZpSubgroup(_g, _p, differentQ);

        // create the public key
        List<ZpGroupElement> pubKeys = new ArrayList<ZpGroupElement>();
        pubKeys.add(new ZpGroupElement(_g, smallGroup));
        pubKeys.add(new ZpGroupElement(_g, smallGroup));
        ElGamalPublicKey elGamalPublicKeyDifferentGroup =
            new ElGamalPublicKey(pubKeys, smallGroup);

        new ElGamalKeyPair(_elGamalPrivateKey,
            elGamalPublicKeyDifferentGroup);
    }

    @Test
    public void givenKeyPairWhenGetPublicKeyThenExpectedValues() {

        ElGamalPublicKey returnedElGamalPublicKey =
            _elGamalKeyPair.getPublicKeys();

        String errorMsg =
            "The returned ElGamal public key does not have the expected values";
        assertEquals(errorMsg, _elGamalPublicKey, returnedElGamalPublicKey);
    }

    @Test
    public void givenKeyPairWhenGetPrivateKeyThenExpectedValues() {

        ElGamalPrivateKey returnedElGamalPrivateKey =
            _elGamalKeyPair.getPrivateKeys();

        String errorMsg =
            "The returned ElGamal private key does not have the expected values";
        assertEquals(errorMsg, _elGamalPrivateKey,
            returnedElGamalPrivateKey);
    }
}
