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

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.elgamal.cryptoapi.Ciphertext;
import com.scytl.cryptolib.mathematical.groups.impl.ZpGroupElement;
import com.scytl.cryptolib.mathematical.groups.impl.ZpSubgroup;
import com.scytl.products.ov.validation.utils.ElGamalHelper;
import org.junit.Test;

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

import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;

public class ElGamalHelperTest {

    @Test
    public void concatenate_elGamal_ciphertext_0_elements() throws GeneralCryptoLibException {
        List<ZpGroupElement> elements = generateFakeCiphertext(0).getElements();
        byte[] bytes = ElGamalHelper.concatValues(elements);

        assertThat(bytes.length, is(0));
    }

    @Test
    public void concatenate_elGamal_ciphertext_1_element() throws GeneralCryptoLibException {
        List<ZpGroupElement> elements = generateFakeCiphertext(1).getElements();
        byte[] bytes = ElGamalHelper.concatValues(elements);

        assertThat(bytes, is(not(nullValue())));

        byte[] element0 = elements.get(0).getValue().toByteArray();
        int expectedLength = element0.length;
        assertThat(bytes.length, is(expectedLength));

        byte[] expectedValue = new byte[expectedLength];
        System.arraycopy(element0, 0, expectedValue, 0, element0.length);

        assertThat(bytes, is(expectedValue));

    }

    @Test
    public void concatenate_elGamal_ciphertext_2_elements() throws GeneralCryptoLibException {
        List<ZpGroupElement> elements = generateFakeCiphertext(2).getElements();
        byte[] bytes = ElGamalHelper.concatValues(elements);

        assertThat(bytes, is(not(nullValue())));

        byte[] element0 = elements.get(0).getValue().toByteArray();
        byte[] element1 = elements.get(1).getValue().toByteArray();
        int expectedLength = element0.length + element1.length;
        assertThat(bytes.length, is(expectedLength));

        byte[] expectedValue = new byte[expectedLength];
        System.arraycopy(element0, 0, expectedValue, 0, element0.length);
        System.arraycopy(element1, 0, expectedValue, element0.length, element1.length);

        assertThat(bytes, is(expectedValue));
    }

    @Test
    public void concatenate_elGamal_ciphertext_4_elements() throws GeneralCryptoLibException {
        List<ZpGroupElement> elements = generateFakeCiphertext(4).getElements();
        byte[] bytes = ElGamalHelper.concatValues(elements);

        assertThat(bytes, is(not(nullValue())));

        byte[] element0 = elements.get(0).getValue().toByteArray();
        byte[] element1 = elements.get(1).getValue().toByteArray();
        byte[] element2 = elements.get(2).getValue().toByteArray();
        byte[] element3 = elements.get(3).getValue().toByteArray();
        int expectedLength = element0.length + element1.length + element2.length + element3.length;
        assertThat(bytes.length, is(expectedLength));

        byte[] expectedValue = new byte[expectedLength];
        System.arraycopy(element0, 0, expectedValue, 0, element0.length);
        System.arraycopy(element1, 0, expectedValue, element0.length, element1.length);
        System.arraycopy(element2, 0, expectedValue, element0.length + element1.length, element2.length);
        System.arraycopy(element3, 0, expectedValue, element0.length + element1.length + element2.length, element1.length);

        assertThat(bytes, is(expectedValue));
    }

    private Ciphertext generateFakeCiphertext(int size) throws GeneralCryptoLibException {

        BigInteger p = new BigInteger("67555108767603707298738874065797424621214999980483524802737421636930165840299");
        BigInteger q = new BigInteger("33777554383801853649369437032898712310607499990241762401368710818465082920149");
        BigInteger g = new BigInteger("3");

        ZpSubgroup group = new ZpSubgroup(g, p, q);

        return () -> {
            List<ZpGroupElement> elements = new ArrayList<>(size);
            try {
                for (int i = 0; i < size; i++) {
                    if (i % 2 == 0) {
                        elements.add(new ZpGroupElement(new BigInteger("33777554383801853649369437032898712310607499990241762401368710818465082920149"), group));
                    } else {
                        elements.add(new ZpGroupElement(new BigInteger("777554383801853649369437032898712310607499990241762401368710818465082920149"), group));
                    }
                }
            } catch (GeneralCryptoLibException e) {
                e.printStackTrace();
            }
            return elements;
        };
    }

}
