package meerkat.mixer.proofs.concrete;

import meerkat.crypto.concrete.ECElGamalEncryption;
import meerkat.mixer.ECParamTestBase;
import meerkat.mixer.proofs.SigmaProtocol;
import meerkat.mixer.proofs.SigmaProtocolTest;
import meerkat.mixer.proofs.concrete.SchnorrDlogEquivalence;
import meerkat.mixer.proofs.concrete.Statements;
import meerkat.protobuf.Mixing;
import org.spongycastle.math.ec.ECPoint;
import org.factcenter.qilin.primitives.concrete.ECGroup;
import org.factcenter.qilin.util.Pair;

import java.math.BigInteger;

/**
 * Created by talm on 12/01/17.
 */
public class DlogStatementSchnorrSigmaTest extends
        SigmaProtocolTest<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> {

    ECParamTestBase ecParams;
    Statements statementGenerator;
    ECElGamalEncryption encryptor;
    ECGroup group;

    Statements.DlogStatement statement;
    Statements.DlogStatementWitness witness;
    SchnorrDlogEquivalence.Prover prover;
    SchnorrDlogEquivalence.Verifier verifier;
    SchnorrDlogEquivalence.Simulator simulator;

    public DlogStatementSchnorrSigmaTest() {
        ecParams = new ECParamTestBase();
        encryptor = ecParams.enc;
        group = encryptor.getGroup();
        this.statementGenerator = new Statements(ecParams.enc);
    }


    Pair<Statements.DlogStatement, Statements.DlogStatementWitness> returnRandomTrueStatement() {
        BigInteger x = encryptor.generateRandomExponent(rand);
        ECPoint a = group.multiply(statementGenerator.g, x);
        ECPoint b = group.multiply(statementGenerator.h, x);
        Statements.DlogStatement statement = statementGenerator.new DlogStatement(a, b);
        Statements.DlogStatementWitness witness = statementGenerator.new DlogStatementWitness(x);

        return new Pair<>(statement, witness);
    }

    Statements.DlogStatement returnRandomFalseStatement() {
        ECPoint a = group.sample(rand);
        ECPoint b = group.sample(rand);

        return statementGenerator.new DlogStatement(a, b);
    }

    @Override
    protected void generateRandomTrueStatement() {
        Pair<Statements.DlogStatement, Statements.DlogStatementWitness> sw = returnRandomTrueStatement();
        this.statement = sw.a;
        this.witness = sw.b;
    }

    @Override
    protected void generateRandomFalseStatement() {
        witness = null;
        statement = returnRandomFalseStatement();
    }

    @Override
    protected SigmaProtocol.Prover<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> getNewProver() {
        prover = new SchnorrDlogEquivalence.Prover(encryptor, rand, statement, witness);
        return prover;
    }

    @Override
    protected SigmaProtocol.Verifier<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> getNewVerifier() {
        verifier = new SchnorrDlogEquivalence.Verifier(encryptor, statement);
        return verifier;
    }

    @Override
    protected SigmaProtocol.Simulator<Mixing.Mix2Proof.DlogProof.FirstMessage, Mixing.Mix2Proof.DlogProof.FinalMessage> getNewSimulator() {
        simulator = new SchnorrDlogEquivalence.Simulator(encryptor, rand, statement);
        return simulator;
    }

    @Override
    protected BigInteger getChallengeModulus() {
        return group.orderUpperBound();
    }
}