package meerkat.mixer.proofs.concrete;

import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.crypto.concrete.Util;
import meerkat.mixer.ECParamTestBase;
import meerkat.mixer.Utils;
import meerkat.protobuf.ConcreteCrypto;
import meerkat.protobuf.Crypto;
import meerkat.protobuf.Mixing;
import meerkat.protobuf.Voting;
//import meerkat.protobuf.Voting.PlaintextBallot;
import org.spongycastle.math.ec.ECPoint;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

/**
 * Created by Tzlil on 12/31/2015.
 */
public class Mix2ProofTest extends ECParamTestBase {
    Mix2nizk nizk;
    meerkat.mixer.proofs.Mix2nizk.Verifier verifier ;
    meerkat.mixer.proofs.Mix2nizk.Prover prover ;

    @Before
    public void setup() throws Exception {
        nizk = new Mix2nizk(rand, enc);
        verifier = nizk;
        prover = nizk;
    }

    private ECPoint convert2ECPoint(ConcreteCrypto.GroupElement bs){
        return enc.decodeElement(bs);
    }

    public void oneZKPTest() throws InvalidProtocolBufferException {
        Voting.PlaintextBallot msg1 = Utils.genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15.
        Voting.PlaintextBallot msg2 = Utils.genRandomBallot(2,3,16);
        Crypto.EncryptionRandomness r1 = enc.generateRandomness(rand);
        Crypto.EncryptionRandomness r2 = enc.generateRandomness(rand);

        Crypto.RerandomizableEncryptedMessage e1 = enc.encrypt(msg1, enc.generateRandomness(rand));
        Crypto.RerandomizableEncryptedMessage e2 = enc.encrypt(msg2, enc.generateRandomness(rand));
        Crypto.RerandomizableEncryptedMessage e1New = enc.rerandomize(e1, r1);
        Crypto.RerandomizableEncryptedMessage e2New = enc.rerandomize(e2, r2);

        assertEquals (Util.decrypt(Voting.PlaintextBallot.class, key, group, e1),    msg1);
        assertEquals (Util.decrypt(Voting.PlaintextBallot.class, key, group, e1New), msg1);
        assertEquals (Util.decrypt(Voting.PlaintextBallot.class, key, group, e2),    msg2);
        assertEquals (Util.decrypt(Voting.PlaintextBallot.class, key, group, e2New), msg2);

        ECPoint g = group.getGenerator();
        ECPoint h = enc.getElGamalPK().getPK();

        ConcreteCrypto.ElGamalCiphertext e1ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(e1);
        ConcreteCrypto.ElGamalCiphertext e2ElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(e2);
        ConcreteCrypto.ElGamalCiphertext e1TagElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(e1New);
        ConcreteCrypto.ElGamalCiphertext e2TagElGamal = ECElGamalEncryption.RerandomizableEncryptedMessage2ElGamalCiphertext(e2New);


        assertEquals (g.multiply(enc.extractRandomness(r1)),
                group.add(convert2ECPoint(e1TagElGamal.getC1()),group.negate(convert2ECPoint(e1ElGamal.getC1()))));
        assertEquals (h.multiply(enc.extractRandomness(r1)),
                group.add(convert2ECPoint(e1TagElGamal.getC2()),group.negate(convert2ECPoint(e1ElGamal.getC2()))));
        assertEquals (g.multiply(enc.extractRandomness(r2)),
                group.add(convert2ECPoint(e2TagElGamal.getC1()),group.negate(convert2ECPoint(e2ElGamal.getC1()))));
        assertEquals (h.multiply(enc.extractRandomness(r2)),
                group.add(convert2ECPoint(e2TagElGamal.getC2()),group.negate(convert2ECPoint(e2ElGamal.getC2()))));


        Mixing.Mix2Proof proof = prover.prove(e1,e2,e1New,e2New,false,0,0,0, 0, r1,r2);

        assertTrue (verifier.verify(e1,e2,e1New,e2New, proof));
    }

    @Test
    public void Mix2ProofTest() throws InvalidProtocolBufferException {

        int tests = 1000;

        for (int i = 0; i < tests; i ++){
            System.out.println("ZKP test #" + i);
            oneZKPTest();
        }
    }
}
