/*
 * 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.Collections.singletonList;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

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.ElGamalPublicKey;
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.proofs.bean.ProofPreComputedValues;
import com.scytl.cryptolib.securerandom.cryptoapi.CryptoAPIRandomInteger;

/**
 * Tests of {@link ORProofPreComputer}.
 */
public class ORProofPreComputerTest {
    private static final int ELEMENT_COUNT = 3;

    private static final BigInteger Z0 = BigInteger.ONE;

    private static final BigInteger Z1 = BigInteger.valueOf(2);

    private static final BigInteger Z2 = BigInteger.valueOf(3);

    private ZpSubgroup group;

    private ElGamalPublicKey publicKey;

    private CryptoAPIRandomInteger random;

    private ORProofPreComputer preComputer;

    @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);

        random = mock(CryptoAPIRandomInteger.class);
        when(random.nextRandomByBits(anyInt())).thenReturn(Z0, Z1, Z2);

        preComputer = new ORProofPreComputer(publicKey, ELEMENT_COUNT);
    }

    @Test
    public void testPreCompute() throws GeneralCryptoLibException {
        ProofPreComputedValues values = preComputer.preCompute(random);

        List<Exponent> exponents = values.getExponents();
        assertEquals(ELEMENT_COUNT, exponents.size());
        assertEquals(new Exponent(group.getQ(), Z0), exponents.get(0));
        assertEquals(new Exponent(group.getQ(), Z1), exponents.get(1));
        assertEquals(new Exponent(group.getQ(), Z2), exponents.get(2));

        List<ZpGroupElement> outputs = values.getPhiOutputs();
        assertEquals(ELEMENT_COUNT * 2, outputs.size());
        ZpGroupElement g = group.getGenerator();
        ZpGroupElement h = publicKey.getKeys().get(0);
        assertEquals(g.exponentiate(exponents.get(0)), outputs.get(0));
        assertEquals(h.exponentiate(exponents.get(0)), outputs.get(1));
        assertEquals(g.exponentiate(exponents.get(1)), outputs.get(2));
        assertEquals(h.exponentiate(exponents.get(1)), outputs.get(3));
        assertEquals(g.exponentiate(exponents.get(2)), outputs.get(4));
        assertEquals(h.exponentiate(exponents.get(2)), outputs.get(5));
    }
}
