/*
 * 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.mixnet.commons.tools;

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

import org.junit.Assert;
import org.junit.Test;

import com.scytl.cryptolib.api.exceptions.CryptoLibException;
import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.elgamal.bean.CiphertextImpl;
import com.scytl.cryptolib.elgamal.cryptoapi.Ciphertext;
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.products.ov.mixnet.commons.ballots.ElGamalEncryptedBallots;

public class RandomOracleHashTest {

    @Test
    public void return_different_hash_the_second_time() throws GeneralCryptoLibException {

        BigInteger q = new BigInteger("4176867913");

        RandomOracleHash randomOracleHash = new RandomOracleHash(q);
        randomOracleHash.addDataToRO(q);

        Exponent value1 = randomOracleHash.getHash();
        randomOracleHash.addDataToRO("1");
        Exponent value2 = randomOracleHash.getHash();

        Assert.assertNotEquals(value1, value2);
    }

    @Test
    public void return_same_hash_for_equal_ciphertexts_matrix()
            throws GeneralCryptoLibException {

        BigInteger q = new BigInteger("4176867913");

        RandomOracleHash randomOracleHash1 = new RandomOracleHash(q);
        Ciphertext[][] ciphertexts1 = getMockedCiphertexts();
        randomOracleHash1.addDataToRO(ciphertexts1);

        RandomOracleHash randomOracleHash2 = new RandomOracleHash(q);
        Ciphertext[][] ciphertexts2 = getCopyOfCiphertexts(ciphertexts1);
        randomOracleHash2.addDataToRO(ciphertexts2);

        Exponent value1 = randomOracleHash1.getHash();
        randomOracleHash1.addDataToRO("1");
        Exponent value2 = randomOracleHash2.getHash();

        Assert.assertEquals(value1, value2);
    }

    private Ciphertext[][] getMockedCiphertexts() {

        try {
            BigInteger p =
                new BigInteger("114727648638092901303037950596653216698134713713320757469185195847827007146277");

            BigInteger q = new BigInteger("4176867913");

            BigInteger g =
                new BigInteger("64234935082206209924651906168426787772383972472097293774232814781118017724241");

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

            List<Ciphertext> ballots = new ArrayList<>();

            for (int i = 0; i < 6; i++) {
                final List<ZpGroupElement> elements = new ArrayList<>();
                elements.add(GroupTools.getRandomElement(group));
                elements.add(GroupTools.getRandomElement(group));
                final CiphertextImpl encryptedBallot =
                    new CiphertextImpl(elements.get(0), elements.subList(1, elements.size()));
                ballots.add(encryptedBallot);
            }

            final ElGamalEncryptedBallots encryptedBallots = new ElGamalEncryptedBallots(ballots);

            return MatrixArranger.arrangeInCiphertextMatrix(encryptedBallots, 2, 3);

        } catch (GeneralCryptoLibException e) {
            throw new CryptoLibException(e);
        }
    }

    private Ciphertext[][] getCopyOfCiphertexts(final Ciphertext[][] ciphertexts) throws GeneralCryptoLibException {
        int m = ciphertexts.length;
        int n = ciphertexts[0].length;
        Ciphertext[][] result = new CiphertextImpl[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                Ciphertext ciphertext = ciphertexts[i][j];
                result[i][j] = new CiphertextImpl(ciphertext.getGamma(), ciphertext.getPhis());
            }
        }
        return result;
    }
}
